[SETUPLIB] Use for-loops instead of while-loops to enumerate linked lists in the...
[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 for (Entry1 = List->DiskListHead.Flink;
328 Entry1 != &List->DiskListHead;
329 Entry1 = Entry1->Flink)
330 {
331 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
332
333 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
334 Entry2 != &DiskEntry->PrimaryPartListHead;
335 Entry2 = Entry2->Flink)
336 {
337 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
338
339 PartEntry->DriveLetter = 0;
340
341 if (PartEntry->IsPartitioned &&
342 !IsContainerPartition(PartEntry->PartitionType))
343 {
344 if (IsRecognizedPartition(PartEntry->PartitionType) ||
345 (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
346 PartEntry->SectorCount.QuadPart != 0LL))
347 {
348 if (Letter <= L'Z')
349 {
350 PartEntry->DriveLetter = Letter;
351 Letter++;
352 }
353 }
354 }
355 }
356 }
357
358 /* Assign drive letters to logical drives */
359 for (Entry1 = List->DiskListHead.Flink;
360 Entry1 != &List->DiskListHead;
361 Entry1 = Entry1->Flink)
362 {
363 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
364
365 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
366 Entry2 != &DiskEntry->LogicalPartListHead;
367 Entry2 = Entry2->Flink)
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 }
388 }
389
390 static NTSTATUS
391 NTAPI
392 DiskIdentifierQueryRoutine(
393 PWSTR ValueName,
394 ULONG ValueType,
395 PVOID ValueData,
396 ULONG ValueLength,
397 PVOID Context,
398 PVOID EntryContext)
399 {
400 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
401 UNICODE_STRING NameU;
402
403 if (ValueType == REG_SZ &&
404 ValueLength == 20 * sizeof(WCHAR))
405 {
406 NameU.Buffer = (PWCHAR)ValueData;
407 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
408 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
409
410 NameU.Buffer = (PWCHAR)ValueData + 9;
411 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
412
413 return STATUS_SUCCESS;
414 }
415
416 return STATUS_UNSUCCESSFUL;
417 }
418
419 static NTSTATUS
420 NTAPI
421 DiskConfigurationDataQueryRoutine(
422 PWSTR ValueName,
423 ULONG ValueType,
424 PVOID ValueData,
425 ULONG ValueLength,
426 PVOID Context,
427 PVOID EntryContext)
428 {
429 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
430 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
431 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
432 ULONG i;
433
434 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
435 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
436 return STATUS_UNSUCCESSFUL;
437
438 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
439
440 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
441 #if 0
442 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
443 FullResourceDescriptor->PartialResourceList.Revision != 1)
444 return STATUS_UNSUCCESSFUL;
445 #endif
446
447 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
448 {
449 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
450 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
451 continue;
452
453 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
454 BiosDiskEntry->DiskGeometry = *DiskGeometry;
455
456 return STATUS_SUCCESS;
457 }
458
459 return STATUS_UNSUCCESSFUL;
460 }
461
462 static NTSTATUS
463 NTAPI
464 SystemConfigurationDataQueryRoutine(
465 PWSTR ValueName,
466 ULONG ValueType,
467 PVOID ValueData,
468 ULONG ValueLength,
469 PVOID Context,
470 PVOID EntryContext)
471 {
472 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
473 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
474 ULONG i;
475
476 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
477 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
478 return STATUS_UNSUCCESSFUL;
479
480 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
481
482 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
483 #if 0
484 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
485 FullResourceDescriptor->PartialResourceList.Revision != 1)
486 return STATUS_UNSUCCESSFUL;
487 #endif
488
489 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
490 {
491 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
492 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
493 continue;
494
495 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(ProcessHeap, 0,
496 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
497 if (*Int13Drives == NULL)
498 return STATUS_NO_MEMORY;
499
500 memcpy(*Int13Drives,
501 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
502 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
503 return STATUS_SUCCESS;
504 }
505
506 return STATUS_UNSUCCESSFUL;
507 }
508
509
510 static VOID
511 EnumerateBiosDiskEntries(
512 IN PPARTLIST PartList)
513 {
514 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
515 WCHAR Name[120];
516 ULONG AdapterCount;
517 ULONG DiskCount;
518 NTSTATUS Status;
519 PCM_INT13_DRIVE_PARAMETER Int13Drives;
520 PBIOSDISKENTRY BiosDiskEntry;
521
522 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
523
524 memset(QueryTable, 0, sizeof(QueryTable));
525
526 QueryTable[1].Name = L"Configuration Data";
527 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
528 Int13Drives = NULL;
529 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
530 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
531 &QueryTable[1],
532 (PVOID)&Int13Drives,
533 NULL);
534 if (!NT_SUCCESS(Status))
535 {
536 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
537 return;
538 }
539
540 AdapterCount = 0;
541 while (TRUE)
542 {
543 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
544 L"%s\\%lu",
545 ROOT_NAME, AdapterCount);
546 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
547 Name,
548 &QueryTable[2],
549 NULL,
550 NULL);
551 if (!NT_SUCCESS(Status))
552 {
553 break;
554 }
555
556 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
557 L"%s\\%lu\\DiskController",
558 ROOT_NAME, AdapterCount);
559 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
560 Name,
561 &QueryTable[2],
562 NULL,
563 NULL);
564 if (NT_SUCCESS(Status))
565 {
566 while (TRUE)
567 {
568 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
569 L"%s\\%lu\\DiskController\\0",
570 ROOT_NAME, AdapterCount);
571 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
572 Name,
573 &QueryTable[2],
574 NULL,
575 NULL);
576 if (!NT_SUCCESS(Status))
577 {
578 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
579 return;
580 }
581
582 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
583 L"%s\\%lu\\DiskController\\0\\DiskPeripheral",
584 ROOT_NAME, AdapterCount);
585 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
586 Name,
587 &QueryTable[2],
588 NULL,
589 NULL);
590 if (NT_SUCCESS(Status))
591 {
592 QueryTable[0].Name = L"Identifier";
593 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
594 QueryTable[1].Name = L"Configuration Data";
595 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
596
597 DiskCount = 0;
598 while (TRUE)
599 {
600 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
601 if (BiosDiskEntry == NULL)
602 {
603 break;
604 }
605
606 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
607 L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu",
608 ROOT_NAME, AdapterCount, DiskCount);
609 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
610 Name,
611 QueryTable,
612 (PVOID)BiosDiskEntry,
613 NULL);
614 if (!NT_SUCCESS(Status))
615 {
616 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
617 break;
618 }
619
620 BiosDiskEntry->DiskNumber = DiskCount;
621 BiosDiskEntry->Recognized = FALSE;
622
623 if (DiskCount < Int13Drives[0].NumberDrives)
624 {
625 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
626 }
627 else
628 {
629 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
630 }
631
632 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
633
634 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
635 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
636 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
637 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
638 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
639 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
640 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
641 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
642 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
643 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
644 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
645
646 DiskCount++;
647 }
648 }
649
650 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
651 return;
652 }
653 }
654
655 AdapterCount++;
656 }
657
658 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
659
660 #undef ROOT_NAME
661 }
662
663
664
665 /*
666 * Inserts the disk region represented by PartEntry into either the primary
667 * or the logical partition list of the given disk.
668 * The lists are kept sorted by increasing order of start sectors.
669 * Of course no disk region should overlap at all with one another.
670 */
671 static
672 VOID
673 InsertDiskRegion(
674 IN PDISKENTRY DiskEntry,
675 IN PPARTENTRY PartEntry,
676 IN BOOLEAN LogicalPartition)
677 {
678 PLIST_ENTRY List;
679 PLIST_ENTRY Entry;
680 PPARTENTRY PartEntry2;
681
682 /* Use the correct partition list */
683 if (LogicalPartition)
684 List = &DiskEntry->LogicalPartListHead;
685 else
686 List = &DiskEntry->PrimaryPartListHead;
687
688 /* Find the first disk region before which we need to insert the new one */
689 for (Entry = List->Flink; Entry != List; Entry = Entry->Flink)
690 {
691 PartEntry2 = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
692
693 /* Ignore any unused empty region */
694 if ((PartEntry2->PartitionType == PARTITION_ENTRY_UNUSED &&
695 PartEntry2->StartSector.QuadPart == 0) || PartEntry2->SectorCount.QuadPart == 0)
696 {
697 continue;
698 }
699
700 /* If the current region ends before the one to be inserted, try again */
701 if (PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1 < PartEntry->StartSector.QuadPart)
702 continue;
703
704 /*
705 * One of the disk region boundaries crosses the desired region
706 * (it starts after the desired region, or ends before the end
707 * of the desired region): this is an impossible situation because
708 * disk regions (partitions) cannot overlap!
709 * Throw an error and bail out.
710 */
711 if (max(PartEntry->StartSector.QuadPart, PartEntry2->StartSector.QuadPart)
712 <=
713 min( PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
714 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1))
715 {
716 DPRINT1("Disk region overlap problem, stopping there!\n"
717 "Partition to be inserted:\n"
718 " StartSector = %I64u ; EndSector = %I64u\n"
719 "Existing disk region:\n"
720 " StartSector = %I64u ; EndSector = %I64u\n",
721 PartEntry->StartSector.QuadPart,
722 PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
723 PartEntry2->StartSector.QuadPart,
724 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1);
725 return;
726 }
727
728 /* We have found the first region before which the new one has to be inserted */
729 break;
730 }
731
732 /* Insert the disk region */
733 InsertTailList(Entry, &PartEntry->ListEntry);
734 }
735
736 static
737 PPARTENTRY
738 CreateInsertBlankRegion(
739 IN PDISKENTRY DiskEntry,
740 IN OUT PLIST_ENTRY ListHead,
741 IN ULONGLONG StartSector,
742 IN ULONGLONG SectorCount,
743 IN BOOLEAN LogicalSpace)
744 {
745 PPARTENTRY NewPartEntry;
746
747 NewPartEntry = RtlAllocateHeap(ProcessHeap,
748 HEAP_ZERO_MEMORY,
749 sizeof(PARTENTRY));
750 if (NewPartEntry == NULL)
751 return NULL;
752
753 NewPartEntry->DiskEntry = DiskEntry;
754
755 NewPartEntry->IsPartitioned = FALSE;
756 NewPartEntry->FormatState = Unformatted;
757 NewPartEntry->FileSystem = NULL;
758
759 NewPartEntry->StartSector.QuadPart = StartSector;
760 NewPartEntry->SectorCount.QuadPart = SectorCount;
761
762 DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
763 DPRINT1("Last Sector : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
764 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
765
766 /* Insert the table into the list */
767 InsertTailList(ListHead, &NewPartEntry->ListEntry);
768
769 return NewPartEntry;
770 }
771
772 static
773 // BOOLEAN
774 PPARTENTRY
775 InitializePartitionEntry(
776 IN PDISKENTRY DiskEntry,
777 IN PPARTENTRY PartEntry,
778 IN ULONGLONG SectorCount,
779 IN BOOLEAN AutoCreate)
780 {
781 PPARTENTRY NewPartEntry;
782
783 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
784
785 if ((AutoCreate != FALSE) ||
786 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
787 PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
788 {
789 DPRINT1("Convert existing partition entry\n");
790
791 /* Convert current entry to 'new (unformatted)' */
792 PartEntry->IsPartitioned = TRUE;
793 PartEntry->New = TRUE;
794 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
795 PartEntry->FormatState = Unformatted;
796 PartEntry->FileSystem = NULL;
797 PartEntry->AutoCreate = AutoCreate;
798 PartEntry->BootIndicator = FALSE;
799 PartEntry->LogicalPartition = FALSE;
800
801 NewPartEntry = PartEntry;
802 }
803 else
804 {
805 DPRINT1("Add new partition entry\n");
806
807 /* Insert and initialize a new partition entry */
808 NewPartEntry = RtlAllocateHeap(ProcessHeap,
809 HEAP_ZERO_MEMORY,
810 sizeof(PARTENTRY));
811 if (NewPartEntry == NULL)
812 return NULL;
813
814 /* Insert the new entry into the list */
815 InsertTailList(&PartEntry->ListEntry,
816 &NewPartEntry->ListEntry);
817
818 NewPartEntry->DiskEntry = DiskEntry;
819
820 NewPartEntry->IsPartitioned = TRUE;
821 NewPartEntry->New = TRUE;
822 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
823 NewPartEntry->FormatState = Unformatted;
824 NewPartEntry->FileSystem = NULL;
825 NewPartEntry->BootIndicator = FALSE;
826 NewPartEntry->LogicalPartition = FALSE;
827
828 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
829 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
830 NewPartEntry->StartSector.QuadPart;
831
832 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
833 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
834 }
835
836 DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
837 DPRINT1("Last Sector : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
838 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
839
840 return NewPartEntry;
841 }
842
843
844 static
845 VOID
846 AddPartitionToDisk(
847 IN ULONG DiskNumber,
848 IN PDISKENTRY DiskEntry,
849 IN ULONG PartitionIndex,
850 IN BOOLEAN LogicalPartition)
851 {
852 NTSTATUS Status;
853 PPARTITION_INFORMATION PartitionInfo;
854 PPARTENTRY PartEntry;
855 HANDLE FileHandle;
856 OBJECT_ATTRIBUTES ObjectAttributes;
857 IO_STATUS_BLOCK IoStatusBlock;
858 WCHAR Buffer[MAX_PATH];
859 UNICODE_STRING Name;
860 UCHAR LabelBuffer[sizeof(FILE_FS_VOLUME_INFORMATION) + 256 * sizeof(WCHAR)];
861 PFILE_FS_VOLUME_INFORMATION LabelInfo = (PFILE_FS_VOLUME_INFORMATION)LabelBuffer;
862
863 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
864
865 if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED ||
866 ((LogicalPartition != FALSE) && IsContainerPartition(PartitionInfo->PartitionType)))
867 {
868 return;
869 }
870
871 PartEntry = RtlAllocateHeap(ProcessHeap,
872 HEAP_ZERO_MEMORY,
873 sizeof(PARTENTRY));
874 if (PartEntry == NULL)
875 return;
876
877 PartEntry->DiskEntry = DiskEntry;
878
879 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
880 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
881
882 PartEntry->BootIndicator = PartitionInfo->BootIndicator;
883 PartEntry->PartitionType = PartitionInfo->PartitionType;
884 PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
885
886 PartEntry->LogicalPartition = LogicalPartition;
887 PartEntry->IsPartitioned = TRUE;
888 PartEntry->OnDiskPartitionNumber = PartitionInfo->PartitionNumber;
889 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
890 PartEntry->PartitionIndex = PartitionIndex;
891
892 if (IsContainerPartition(PartEntry->PartitionType))
893 {
894 PartEntry->FormatState = Unformatted;
895 PartEntry->FileSystem = NULL;
896
897 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
898 DiskEntry->ExtendedPartition = PartEntry;
899 }
900 else if (IsRecognizedPartition(PartEntry->PartitionType))
901 {
902 ASSERT(PartitionInfo->RecognizedPartition);
903
904 PartEntry->FileSystem = GetFileSystem(PartEntry);
905 if (PartEntry->FileSystem)
906 PartEntry->FormatState = Preformatted;
907 else
908 PartEntry->FormatState = Unformatted;
909 // PartEntry->FormatState = UnknownFormat;
910 }
911 else
912 {
913 /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
914 PartEntry->FormatState = UnknownFormat;
915 }
916
917 /* Initialize the partition volume label */
918 RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel));
919
920 /* Open the volume, ignore any errors */
921 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
922 L"\\Device\\Harddisk%lu\\Partition%lu",
923 DiskEntry->DiskNumber,
924 PartEntry->PartitionNumber);
925 RtlInitUnicodeString(&Name, Buffer);
926
927 InitializeObjectAttributes(&ObjectAttributes,
928 &Name,
929 OBJ_CASE_INSENSITIVE,
930 NULL,
931 NULL);
932
933 Status = NtOpenFile(&FileHandle,
934 FILE_READ_DATA | SYNCHRONIZE,
935 &ObjectAttributes,
936 &IoStatusBlock,
937 FILE_SHARE_READ | FILE_SHARE_WRITE,
938 FILE_SYNCHRONOUS_IO_NONALERT);
939 if (NT_SUCCESS(Status))
940 {
941 /* Retrieve the partition volume label */
942 Status = NtQueryVolumeInformationFile(FileHandle,
943 &IoStatusBlock,
944 &LabelBuffer,
945 sizeof(LabelBuffer),
946 FileFsVolumeInformation);
947 /* Close the handle */
948 NtClose(FileHandle);
949
950 /* Check for success */
951 if (NT_SUCCESS(Status))
952 {
953 /* Copy the (possibly truncated) volume label and NULL-terminate it */
954 RtlStringCbCopyNW(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel),
955 LabelInfo->VolumeLabel, LabelInfo->VolumeLabelLength);
956 }
957 else
958 {
959 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status);
960 }
961 }
962 else
963 {
964 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status);
965 }
966
967 InsertDiskRegion(DiskEntry, PartEntry, LogicalPartition);
968 }
969
970 static
971 VOID
972 ScanForUnpartitionedDiskSpace(
973 IN PDISKENTRY DiskEntry)
974 {
975 ULONGLONG StartSector;
976 ULONGLONG SectorCount;
977 ULONGLONG LastStartSector;
978 ULONGLONG LastSectorCount;
979 ULONGLONG LastUnusedSectorCount;
980 PPARTENTRY PartEntry;
981 PPARTENTRY NewPartEntry;
982 PLIST_ENTRY Entry;
983
984 DPRINT("ScanForUnpartitionedDiskSpace()\n");
985
986 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
987 {
988 DPRINT1("No primary partition!\n");
989
990 /* Create a partition entry that represents the empty disk */
991
992 if (DiskEntry->SectorAlignment < 2048)
993 StartSector = 2048ULL;
994 else
995 StartSector = (ULONGLONG)DiskEntry->SectorAlignment;
996 SectorCount = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - StartSector;
997
998 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
999 &DiskEntry->PrimaryPartListHead,
1000 StartSector,
1001 SectorCount,
1002 FALSE);
1003 if (NewPartEntry == NULL)
1004 DPRINT1("Failed to create a new empty region for full disk space!\n");
1005
1006 return;
1007 }
1008
1009 /* Start partition at head 1, cylinder 0 */
1010 if (DiskEntry->SectorAlignment < 2048)
1011 LastStartSector = 2048ULL;
1012 else
1013 LastStartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1014 LastSectorCount = 0ULL;
1015 LastUnusedSectorCount = 0ULL;
1016
1017 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
1018 Entry != &DiskEntry->PrimaryPartListHead;
1019 Entry = Entry->Flink)
1020 {
1021 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1022
1023 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1024 PartEntry->SectorCount.QuadPart != 0ULL)
1025 {
1026 LastUnusedSectorCount =
1027 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
1028
1029 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
1030 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1031 {
1032 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1033
1034 StartSector = LastStartSector + LastSectorCount;
1035 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1036
1037 /* Insert the table into the list */
1038 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1039 &PartEntry->ListEntry,
1040 StartSector,
1041 SectorCount,
1042 FALSE);
1043 if (NewPartEntry == NULL)
1044 {
1045 DPRINT1("Failed to create a new empty region for disk space!\n");
1046 return;
1047 }
1048 }
1049
1050 LastStartSector = PartEntry->StartSector.QuadPart;
1051 LastSectorCount = PartEntry->SectorCount.QuadPart;
1052 }
1053 }
1054
1055 /* Check for trailing unpartitioned disk space */
1056 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
1057 {
1058 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
1059
1060 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1061 {
1062 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1063
1064 StartSector = LastStartSector + LastSectorCount;
1065 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1066
1067 /* Append the table to the list */
1068 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1069 &DiskEntry->PrimaryPartListHead,
1070 StartSector,
1071 SectorCount,
1072 FALSE);
1073 if (NewPartEntry == NULL)
1074 {
1075 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1076 return;
1077 }
1078 }
1079 }
1080
1081 if (DiskEntry->ExtendedPartition != NULL)
1082 {
1083 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
1084 {
1085 DPRINT1("No logical partition!\n");
1086
1087 /* Create a partition entry that represents the empty extended partition */
1088
1089 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1090 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
1091
1092 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1093 &DiskEntry->LogicalPartListHead,
1094 StartSector,
1095 SectorCount,
1096 TRUE);
1097 if (NewPartEntry == NULL)
1098 {
1099 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1100 return;
1101 }
1102 NewPartEntry->LogicalPartition = TRUE;
1103
1104 return;
1105 }
1106
1107 /* Start partition at head 1, cylinder 0 */
1108 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1109 LastSectorCount = 0ULL;
1110 LastUnusedSectorCount = 0ULL;
1111
1112 for (Entry = DiskEntry->LogicalPartListHead.Flink;
1113 Entry != &DiskEntry->LogicalPartListHead;
1114 Entry = Entry->Flink)
1115 {
1116 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1117
1118 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1119 PartEntry->SectorCount.QuadPart != 0ULL)
1120 {
1121 LastUnusedSectorCount =
1122 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
1123
1124 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
1125 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1126 {
1127 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1128
1129 StartSector = LastStartSector + LastSectorCount;
1130 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1131
1132 /* Insert the table into the list */
1133 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1134 &PartEntry->ListEntry,
1135 StartSector,
1136 SectorCount,
1137 TRUE);
1138 if (NewPartEntry == NULL)
1139 {
1140 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1141 return;
1142 }
1143 NewPartEntry->LogicalPartition = TRUE;
1144 }
1145
1146 LastStartSector = PartEntry->StartSector.QuadPart;
1147 LastSectorCount = PartEntry->SectorCount.QuadPart;
1148 }
1149 }
1150
1151 /* Check for trailing unpartitioned disk space */
1152 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
1153 {
1154 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart +
1155 DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
1156 DiskEntry->SectorAlignment);
1157
1158 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1159 {
1160 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1161
1162 StartSector = LastStartSector + LastSectorCount;
1163 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1164
1165 /* Append the table to the list */
1166 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1167 &DiskEntry->LogicalPartListHead,
1168 StartSector,
1169 SectorCount,
1170 TRUE);
1171 if (NewPartEntry == NULL)
1172 {
1173 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1174 return;
1175 }
1176 NewPartEntry->LogicalPartition = TRUE;
1177 }
1178 }
1179 }
1180
1181 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1182 }
1183
1184 static
1185 VOID
1186 SetDiskSignature(
1187 IN PPARTLIST List,
1188 IN PDISKENTRY DiskEntry)
1189 {
1190 LARGE_INTEGER SystemTime;
1191 TIME_FIELDS TimeFields;
1192 PLIST_ENTRY Entry2;
1193 PDISKENTRY DiskEntry2;
1194 PUCHAR Buffer;
1195
1196 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
1197
1198 while (TRUE)
1199 {
1200 NtQuerySystemTime(&SystemTime);
1201 RtlTimeToTimeFields(&SystemTime, &TimeFields);
1202
1203 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
1204 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
1205 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
1206 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
1207
1208 if (DiskEntry->LayoutBuffer->Signature == 0)
1209 {
1210 continue;
1211 }
1212
1213 /* Check if the signature already exist */
1214 /* FIXME:
1215 * Check also signatures from disks, which are
1216 * not visible (bootable) by the bios.
1217 */
1218 for (Entry2 = List->DiskListHead.Flink;
1219 Entry2 != &List->DiskListHead;
1220 Entry2 = Entry2->Flink)
1221 {
1222 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
1223
1224 if (DiskEntry != DiskEntry2 &&
1225 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
1226 break;
1227 }
1228
1229 if (Entry2 == &List->DiskListHead)
1230 break;
1231 }
1232 }
1233
1234 static
1235 VOID
1236 UpdateDiskSignatures(
1237 IN PPARTLIST List)
1238 {
1239 PLIST_ENTRY Entry;
1240 PDISKENTRY DiskEntry;
1241
1242 /* Print partition lines */
1243 for (Entry = List->DiskListHead.Flink;
1244 Entry != &List->DiskListHead;
1245 Entry = Entry->Flink)
1246 {
1247 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1248
1249 if (DiskEntry->LayoutBuffer &&
1250 DiskEntry->LayoutBuffer->Signature == 0)
1251 {
1252 SetDiskSignature(List, DiskEntry);
1253 DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
1254 }
1255 }
1256 }
1257
1258 static
1259 VOID
1260 AddDiskToList(
1261 IN HANDLE FileHandle,
1262 IN ULONG DiskNumber,
1263 IN PPARTLIST List)
1264 {
1265 DISK_GEOMETRY DiskGeometry;
1266 SCSI_ADDRESS ScsiAddress;
1267 PDISKENTRY DiskEntry;
1268 IO_STATUS_BLOCK Iosb;
1269 NTSTATUS Status;
1270 PPARTITION_SECTOR Mbr;
1271 PULONG Buffer;
1272 LARGE_INTEGER FileOffset;
1273 WCHAR Identifier[20];
1274 ULONG Checksum;
1275 ULONG Signature;
1276 ULONG i;
1277 PLIST_ENTRY ListEntry;
1278 PBIOSDISKENTRY BiosDiskEntry;
1279 ULONG LayoutBufferSize;
1280 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
1281
1282 /* Retrieve the drive geometry */
1283 Status = NtDeviceIoControlFile(FileHandle,
1284 NULL,
1285 NULL,
1286 NULL,
1287 &Iosb,
1288 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1289 NULL,
1290 0,
1291 &DiskGeometry,
1292 sizeof(DiskGeometry));
1293 if (!NT_SUCCESS(Status))
1294 return;
1295
1296 if (DiskGeometry.MediaType != FixedMedia &&
1297 DiskGeometry.MediaType != RemovableMedia)
1298 {
1299 return;
1300 }
1301
1302 /*
1303 * FIXME: Here we suppose the disk is always SCSI. What if it is
1304 * of another type? To check this we need to retrieve the name of
1305 * the driver the disk device belongs to.
1306 */
1307 Status = NtDeviceIoControlFile(FileHandle,
1308 NULL,
1309 NULL,
1310 NULL,
1311 &Iosb,
1312 IOCTL_SCSI_GET_ADDRESS,
1313 NULL,
1314 0,
1315 &ScsiAddress,
1316 sizeof(ScsiAddress));
1317 if (!NT_SUCCESS(Status))
1318 return;
1319
1320 /*
1321 * Check whether the disk is initialized, by looking at its MBR.
1322 * NOTE that this must be generalized to GPT disks as well!
1323 */
1324
1325 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
1326 0,
1327 DiskGeometry.BytesPerSector);
1328 if (Mbr == NULL)
1329 return;
1330
1331 FileOffset.QuadPart = 0;
1332 Status = NtReadFile(FileHandle,
1333 NULL,
1334 NULL,
1335 NULL,
1336 &Iosb,
1337 (PVOID)Mbr,
1338 DiskGeometry.BytesPerSector,
1339 &FileOffset,
1340 NULL);
1341 if (!NT_SUCCESS(Status))
1342 {
1343 RtlFreeHeap(ProcessHeap, 0, Mbr);
1344 DPRINT1("NtReadFile failed, status=%x\n", Status);
1345 return;
1346 }
1347 Signature = Mbr->Signature;
1348
1349 /* Calculate the MBR checksum */
1350 Checksum = 0;
1351 Buffer = (PULONG)Mbr;
1352 for (i = 0; i < 128; i++)
1353 {
1354 Checksum += Buffer[i];
1355 }
1356 Checksum = ~Checksum + 1;
1357
1358 RtlStringCchPrintfW(Identifier, ARRAYSIZE(Identifier),
1359 L"%08x-%08x-A", Checksum, Signature);
1360 DPRINT("Identifier: %S\n", Identifier);
1361
1362 DiskEntry = RtlAllocateHeap(ProcessHeap,
1363 HEAP_ZERO_MEMORY,
1364 sizeof(DISKENTRY));
1365 if (DiskEntry == NULL)
1366 {
1367 RtlFreeHeap(ProcessHeap, 0, Mbr);
1368 DPRINT1("Failed to allocate a new disk entry.\n");
1369 return;
1370 }
1371
1372 // DiskEntry->Checksum = Checksum;
1373 // DiskEntry->Signature = Signature;
1374 DiskEntry->BiosFound = FALSE;
1375
1376 /*
1377 * Check if this disk has a valid MBR: verify its signature,
1378 * and whether its two first bytes are a valid instruction
1379 * (related to this, see IsThereAValidBootSector() in partlist.c).
1380 */
1381 if (Mbr->Magic != 0xaa55 || (*(PUSHORT)Mbr->BootCode) == 0x0000)
1382 DiskEntry->NoMbr = TRUE;
1383 else
1384 DiskEntry->NoMbr = FALSE;
1385
1386 /* Free the MBR sector buffer */
1387 RtlFreeHeap(ProcessHeap, 0, Mbr);
1388
1389
1390 for (ListEntry = List->BiosDiskListHead.Flink;
1391 ListEntry != &List->BiosDiskListHead;
1392 ListEntry = ListEntry->Flink)
1393 {
1394 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1395 /* FIXME:
1396 * Compare the size from bios and the reported size from driver.
1397 * If we have more than one disk with a zero or with the same signature
1398 * we must create new signatures and reboot. After the reboot,
1399 * it is possible to identify the disks.
1400 */
1401 if (BiosDiskEntry->Signature == Signature &&
1402 BiosDiskEntry->Checksum == Checksum &&
1403 !BiosDiskEntry->Recognized)
1404 {
1405 if (!DiskEntry->BiosFound)
1406 {
1407 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
1408 DiskEntry->BiosFound = TRUE;
1409 BiosDiskEntry->Recognized = TRUE;
1410 }
1411 else
1412 {
1413 // FIXME: What to do?
1414 }
1415 }
1416 }
1417
1418 if (!DiskEntry->BiosFound)
1419 {
1420 #if 0
1421 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1422 return;
1423 #else
1424 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
1425 #endif
1426 }
1427
1428 InitializeListHead(&DiskEntry->PrimaryPartListHead);
1429 InitializeListHead(&DiskEntry->LogicalPartListHead);
1430
1431 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1432 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1433 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1434 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1435
1436 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1437 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
1438 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
1439 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
1440
1441 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1442 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1443 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1444
1445 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1446 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
1447 DiskGeometry.SectorsPerTrack;
1448
1449 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
1450 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1451
1452 DiskEntry->DiskNumber = DiskNumber;
1453 DiskEntry->Port = ScsiAddress.PortNumber;
1454 DiskEntry->Bus = ScsiAddress.PathId;
1455 DiskEntry->Id = ScsiAddress.TargetId;
1456
1457 GetDriverName(DiskEntry);
1458 /*
1459 * Actually it would be more correct somehow to use:
1460 *
1461 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1462 * ULONG ReturnedLength;
1463 *
1464 * Status = NtQueryObject(SomeHandleToTheDisk,
1465 * ObjectNameInformation,
1466 * &NameInfo,
1467 * sizeof(NameInfo),
1468 * &ReturnedLength);
1469 * etc...
1470 *
1471 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1472 */
1473
1474 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1475
1476
1477 /*
1478 * We now retrieve the disk partition layout
1479 */
1480
1481 /* Allocate a layout buffer with 4 partition entries first */
1482 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1483 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1484 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
1485 HEAP_ZERO_MEMORY,
1486 LayoutBufferSize);
1487 if (DiskEntry->LayoutBuffer == NULL)
1488 {
1489 DPRINT1("Failed to allocate the disk layout buffer!\n");
1490 return;
1491 }
1492
1493 /* Keep looping while the drive layout buffer is too small */
1494 for (;;)
1495 {
1496 DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
1497 Status = NtDeviceIoControlFile(FileHandle,
1498 NULL,
1499 NULL,
1500 NULL,
1501 &Iosb,
1502 IOCTL_DISK_GET_DRIVE_LAYOUT,
1503 NULL,
1504 0,
1505 DiskEntry->LayoutBuffer,
1506 LayoutBufferSize);
1507 if (NT_SUCCESS(Status))
1508 break;
1509
1510 if (Status != STATUS_BUFFER_TOO_SMALL)
1511 {
1512 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1513 return;
1514 }
1515
1516 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
1517 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1518 HEAP_ZERO_MEMORY,
1519 DiskEntry->LayoutBuffer,
1520 LayoutBufferSize);
1521 if (NewLayoutBuffer == NULL)
1522 {
1523 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1524 return;
1525 }
1526
1527 DiskEntry->LayoutBuffer = NewLayoutBuffer;
1528 }
1529
1530 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1531
1532 #ifdef DUMP_PARTITION_TABLE
1533 DumpPartitionTable(DiskEntry);
1534 #endif
1535
1536 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1537 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1538 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != PARTITION_ENTRY_UNUSED)
1539 {
1540 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1541 {
1542 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1543 }
1544 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1545 {
1546 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1547 }
1548 else
1549 {
1550 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1551 }
1552 }
1553 else
1554 {
1555 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1556 }
1557
1558 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1559 {
1560 DiskEntry->NewDisk = TRUE;
1561 DiskEntry->LayoutBuffer->PartitionCount = 4;
1562
1563 for (i = 0; i < 4; i++)
1564 {
1565 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1566 }
1567 }
1568 else
1569 {
1570 /* Enumerate and add the first four primary partitions */
1571 for (i = 0; i < 4; i++)
1572 {
1573 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1574 }
1575
1576 /* Enumerate and add the remaining partitions as logical ones */
1577 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1578 {
1579 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1580 }
1581 }
1582
1583 ScanForUnpartitionedDiskSpace(DiskEntry);
1584 }
1585
1586 PPARTLIST
1587 CreatePartitionList(VOID)
1588 {
1589 PPARTLIST List;
1590 OBJECT_ATTRIBUTES ObjectAttributes;
1591 SYSTEM_DEVICE_INFORMATION Sdi;
1592 IO_STATUS_BLOCK Iosb;
1593 ULONG ReturnSize;
1594 NTSTATUS Status;
1595 ULONG DiskNumber;
1596 WCHAR Buffer[MAX_PATH];
1597 UNICODE_STRING Name;
1598 HANDLE FileHandle;
1599
1600 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1601 0,
1602 sizeof(PARTLIST));
1603 if (List == NULL)
1604 return NULL;
1605
1606 List->CurrentDisk = NULL;
1607 List->CurrentPartition = NULL;
1608
1609 List->SystemPartition = NULL;
1610 List->OriginalSystemPartition = NULL;
1611
1612 InitializeListHead(&List->DiskListHead);
1613 InitializeListHead(&List->BiosDiskListHead);
1614
1615 /*
1616 * Enumerate the disks seen by the BIOS; this will be used later
1617 * to map drives seen by NTOS with their corresponding BIOS names.
1618 */
1619 EnumerateBiosDiskEntries(List);
1620
1621 /* Enumerate disks seen by NTOS */
1622 Status = NtQuerySystemInformation(SystemDeviceInformation,
1623 &Sdi,
1624 sizeof(Sdi),
1625 &ReturnSize);
1626 if (!NT_SUCCESS(Status))
1627 {
1628 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status);
1629 RtlFreeHeap(ProcessHeap, 0, List);
1630 return NULL;
1631 }
1632
1633 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1634 {
1635 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
1636 L"\\Device\\Harddisk%lu\\Partition0",
1637 DiskNumber);
1638 RtlInitUnicodeString(&Name, Buffer);
1639
1640 InitializeObjectAttributes(&ObjectAttributes,
1641 &Name,
1642 OBJ_CASE_INSENSITIVE,
1643 NULL,
1644 NULL);
1645
1646 Status = NtOpenFile(&FileHandle,
1647 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1648 &ObjectAttributes,
1649 &Iosb,
1650 FILE_SHARE_READ | FILE_SHARE_WRITE,
1651 FILE_SYNCHRONOUS_IO_NONALERT);
1652 if (NT_SUCCESS(Status))
1653 {
1654 AddDiskToList(FileHandle, DiskNumber, List);
1655 NtClose(FileHandle);
1656 }
1657 }
1658
1659 UpdateDiskSignatures(List);
1660
1661 AssignDriveLetters(List);
1662
1663 /* Search for first usable disk and partition */
1664 if (IsListEmpty(&List->DiskListHead))
1665 {
1666 List->CurrentDisk = NULL;
1667 List->CurrentPartition = NULL;
1668 }
1669 else
1670 {
1671 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1672 DISKENTRY,
1673 ListEntry);
1674
1675 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1676 {
1677 List->CurrentPartition = NULL;
1678 }
1679 else
1680 {
1681 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1682 PARTENTRY,
1683 ListEntry);
1684 }
1685 }
1686
1687 return List;
1688 }
1689
1690 VOID
1691 DestroyPartitionList(
1692 IN PPARTLIST List)
1693 {
1694 PDISKENTRY DiskEntry;
1695 PBIOSDISKENTRY BiosDiskEntry;
1696 PPARTENTRY PartEntry;
1697 PLIST_ENTRY Entry;
1698
1699 /* Release disk and partition info */
1700 while (!IsListEmpty(&List->DiskListHead))
1701 {
1702 Entry = RemoveHeadList(&List->DiskListHead);
1703 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1704
1705 /* Release driver name */
1706 RtlFreeUnicodeString(&DiskEntry->DriverName);
1707
1708 /* Release primary partition list */
1709 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1710 {
1711 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1712 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1713
1714 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1715 }
1716
1717 /* Release logical partition list */
1718 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1719 {
1720 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1721 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1722
1723 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1724 }
1725
1726 /* Release layout buffer */
1727 if (DiskEntry->LayoutBuffer != NULL)
1728 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1729
1730 /* Release disk entry */
1731 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1732 }
1733
1734 /* Release the bios disk info */
1735 while (!IsListEmpty(&List->BiosDiskListHead))
1736 {
1737 Entry = RemoveHeadList(&List->BiosDiskListHead);
1738 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1739
1740 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1741 }
1742
1743 /* Release list head */
1744 RtlFreeHeap(ProcessHeap, 0, List);
1745 }
1746
1747 PDISKENTRY
1748 GetDiskByBiosNumber(
1749 IN PPARTLIST List,
1750 IN ULONG BiosDiskNumber)
1751 {
1752 PDISKENTRY DiskEntry;
1753 PLIST_ENTRY Entry;
1754
1755 /* Loop over the disks and find the correct one */
1756 for (Entry = List->DiskListHead.Flink;
1757 Entry != &List->DiskListHead;
1758 Entry = Entry->Flink)
1759 {
1760 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1761
1762 if (DiskEntry->BiosDiskNumber == BiosDiskNumber)
1763 {
1764 /* Disk found */
1765 return DiskEntry;
1766 }
1767 }
1768
1769 /* Disk not found, stop there */
1770 return NULL;
1771 }
1772
1773 PDISKENTRY
1774 GetDiskByNumber(
1775 IN PPARTLIST List,
1776 IN ULONG DiskNumber)
1777 {
1778 PDISKENTRY DiskEntry;
1779 PLIST_ENTRY Entry;
1780
1781 /* Loop over the disks and find the correct one */
1782 for (Entry = List->DiskListHead.Flink;
1783 Entry != &List->DiskListHead;
1784 Entry = Entry->Flink)
1785 {
1786 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1787
1788 if (DiskEntry->DiskNumber == DiskNumber)
1789 {
1790 /* Disk found */
1791 return DiskEntry;
1792 }
1793 }
1794
1795 /* Disk not found, stop there */
1796 return NULL;
1797 }
1798
1799 PDISKENTRY
1800 GetDiskBySCSI(
1801 IN PPARTLIST List,
1802 IN USHORT Port,
1803 IN USHORT Bus,
1804 IN USHORT Id)
1805 {
1806 PDISKENTRY DiskEntry;
1807 PLIST_ENTRY Entry;
1808
1809 /* Loop over the disks and find the correct one */
1810 for (Entry = List->DiskListHead.Flink;
1811 Entry != &List->DiskListHead;
1812 Entry = Entry->Flink)
1813 {
1814 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1815
1816 if (DiskEntry->Port == Port &&
1817 DiskEntry->Bus == Bus &&
1818 DiskEntry->Id == Id)
1819 {
1820 /* Disk found */
1821 return DiskEntry;
1822 }
1823 }
1824
1825 /* Disk not found, stop there */
1826 return NULL;
1827 }
1828
1829 PDISKENTRY
1830 GetDiskBySignature(
1831 IN PPARTLIST List,
1832 IN ULONG Signature)
1833 {
1834 PDISKENTRY DiskEntry;
1835 PLIST_ENTRY Entry;
1836
1837 /* Loop over the disks and find the correct one */
1838 for (Entry = List->DiskListHead.Flink;
1839 Entry != &List->DiskListHead;
1840 Entry = Entry->Flink)
1841 {
1842 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1843
1844 if (DiskEntry->LayoutBuffer->Signature == Signature)
1845 {
1846 /* Disk found */
1847 return DiskEntry;
1848 }
1849 }
1850
1851 /* Disk not found, stop there */
1852 return NULL;
1853 }
1854
1855 PPARTENTRY
1856 GetPartition(
1857 // IN PPARTLIST List,
1858 IN PDISKENTRY DiskEntry,
1859 IN ULONG PartitionNumber)
1860 {
1861 PPARTENTRY PartEntry;
1862 PLIST_ENTRY Entry;
1863
1864 /* Disk found, loop over the primary partitions first... */
1865 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
1866 Entry != &DiskEntry->PrimaryPartListHead;
1867 Entry = Entry->Flink)
1868 {
1869 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1870
1871 if (PartEntry->PartitionNumber == PartitionNumber)
1872 {
1873 /* Partition found */
1874 return PartEntry;
1875 }
1876 }
1877
1878 /* ... then over the logical partitions if needed */
1879 for (Entry = DiskEntry->LogicalPartListHead.Flink;
1880 Entry != &DiskEntry->LogicalPartListHead;
1881 Entry = Entry->Flink)
1882 {
1883 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1884
1885 if (PartEntry->PartitionNumber == PartitionNumber)
1886 {
1887 /* Partition found */
1888 return PartEntry;
1889 }
1890 }
1891
1892 /* The partition was not found on the disk, stop there */
1893 return NULL;
1894 }
1895
1896 BOOLEAN
1897 GetDiskOrPartition(
1898 IN PPARTLIST List,
1899 IN ULONG DiskNumber,
1900 IN ULONG PartitionNumber OPTIONAL,
1901 OUT PDISKENTRY* pDiskEntry,
1902 OUT PPARTENTRY* pPartEntry OPTIONAL)
1903 {
1904 PDISKENTRY DiskEntry;
1905 PPARTENTRY PartEntry = NULL;
1906
1907 /* Find the disk */
1908 DiskEntry = GetDiskByNumber(List, DiskNumber);
1909 if (!DiskEntry)
1910 return FALSE;
1911
1912 /* If we have a partition (PartitionNumber != 0), find it */
1913 if (PartitionNumber != 0)
1914 {
1915 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
1916 if (!PartEntry)
1917 return FALSE;
1918 ASSERT(PartEntry->DiskEntry == DiskEntry);
1919 }
1920
1921 /* Return the disk (and optionally the partition) */
1922 *pDiskEntry = DiskEntry;
1923 if (pPartEntry) *pPartEntry = PartEntry;
1924 return TRUE;
1925 }
1926
1927 //
1928 // NOTE: Was introduced broken in r6258 by Casper
1929 //
1930 BOOLEAN
1931 SelectPartition(
1932 IN PPARTLIST List,
1933 IN ULONG DiskNumber,
1934 IN ULONG PartitionNumber)
1935 {
1936 PDISKENTRY DiskEntry;
1937 PPARTENTRY PartEntry;
1938
1939 DiskEntry = GetDiskByNumber(List, DiskNumber);
1940 if (!DiskEntry)
1941 return FALSE;
1942
1943 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
1944 if (!PartEntry)
1945 return FALSE;
1946
1947 ASSERT(PartEntry->DiskEntry == DiskEntry);
1948 ASSERT(DiskEntry->DiskNumber == DiskNumber);
1949 ASSERT(PartEntry->PartitionNumber == PartitionNumber);
1950
1951 List->CurrentDisk = DiskEntry;
1952 List->CurrentPartition = PartEntry;
1953 return TRUE;
1954 }
1955
1956 PPARTENTRY
1957 GetNextPartition(
1958 IN PPARTLIST List)
1959 {
1960 PLIST_ENTRY DiskListEntry;
1961 PLIST_ENTRY PartListEntry;
1962 PDISKENTRY DiskEntry;
1963 PPARTENTRY PartEntry;
1964
1965 /* Fail if no disks are available */
1966 if (IsListEmpty(&List->DiskListHead))
1967 return NULL;
1968
1969 /* Check for next usable entry on current disk */
1970 if (List->CurrentPartition != NULL)
1971 {
1972 if (List->CurrentPartition->LogicalPartition)
1973 {
1974 /* Logical partition */
1975
1976 PartListEntry = List->CurrentPartition->ListEntry.Flink;
1977 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
1978 {
1979 /* Next logical partition */
1980 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1981
1982 List->CurrentPartition = PartEntry;
1983 return List->CurrentPartition;
1984 }
1985 else
1986 {
1987 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
1988 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
1989 {
1990 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1991
1992 List->CurrentPartition = PartEntry;
1993 return List->CurrentPartition;
1994 }
1995 }
1996 }
1997 else
1998 {
1999 /* Primary or extended partition */
2000
2001 if (List->CurrentPartition->IsPartitioned &&
2002 IsContainerPartition(List->CurrentPartition->PartitionType))
2003 {
2004 /* First logical partition */
2005 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
2006 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2007 {
2008 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2009
2010 List->CurrentPartition = PartEntry;
2011 return List->CurrentPartition;
2012 }
2013 }
2014 else
2015 {
2016 /* Next primary partition */
2017 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2018 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2019 {
2020 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2021
2022 List->CurrentPartition = PartEntry;
2023 return List->CurrentPartition;
2024 }
2025 }
2026 }
2027 }
2028
2029 /* Search for the first partition entry on the next disk */
2030 for (DiskListEntry = List->CurrentDisk->ListEntry.Flink;
2031 DiskListEntry != &List->DiskListHead;
2032 DiskListEntry = DiskListEntry->Flink)
2033 {
2034 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2035
2036 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
2037 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2038 {
2039 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2040
2041 List->CurrentDisk = DiskEntry;
2042 List->CurrentPartition = PartEntry;
2043 return List->CurrentPartition;
2044 }
2045 }
2046
2047 return NULL;
2048 }
2049
2050 PPARTENTRY
2051 GetPrevPartition(
2052 IN PPARTLIST List)
2053 {
2054 PLIST_ENTRY DiskListEntry;
2055 PLIST_ENTRY PartListEntry;
2056 PDISKENTRY DiskEntry;
2057 PPARTENTRY PartEntry;
2058
2059 /* Fail if no disks are available */
2060 if (IsListEmpty(&List->DiskListHead))
2061 return NULL;
2062
2063 /* Check for previous usable entry on current disk */
2064 if (List->CurrentPartition != NULL)
2065 {
2066 if (List->CurrentPartition->LogicalPartition)
2067 {
2068 /* Logical partition */
2069 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2070 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2071 {
2072 /* Previous logical partition */
2073 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2074 }
2075 else
2076 {
2077 /* Extended partition */
2078 PartEntry = List->CurrentDisk->ExtendedPartition;
2079 }
2080
2081 List->CurrentPartition = PartEntry;
2082 return List->CurrentPartition;
2083 }
2084 else
2085 {
2086 /* Primary or extended partition */
2087
2088 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2089 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2090 {
2091 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2092
2093 if (PartEntry->IsPartitioned &&
2094 IsContainerPartition(PartEntry->PartitionType))
2095 {
2096 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
2097 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2098 }
2099
2100 List->CurrentPartition = PartEntry;
2101 return List->CurrentPartition;
2102 }
2103 }
2104 }
2105
2106 /* Search for the last partition entry on the previous disk */
2107 for (DiskListEntry = List->CurrentDisk->ListEntry.Blink;
2108 DiskListEntry != &List->DiskListHead;
2109 DiskListEntry = DiskListEntry->Blink)
2110 {
2111 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2112
2113 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
2114 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2115 {
2116 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2117
2118 if (PartEntry->IsPartitioned &&
2119 IsContainerPartition(PartEntry->PartitionType))
2120 {
2121 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
2122 if (PartListEntry != &DiskEntry->LogicalPartListHead)
2123 {
2124 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2125
2126 List->CurrentDisk = DiskEntry;
2127 List->CurrentPartition = PartEntry;
2128 return List->CurrentPartition;
2129 }
2130 }
2131 else
2132 {
2133 List->CurrentDisk = DiskEntry;
2134 List->CurrentPartition = PartEntry;
2135 return List->CurrentPartition;
2136 }
2137 }
2138 }
2139
2140 return NULL;
2141 }
2142
2143 // static
2144 FORCEINLINE
2145 BOOLEAN
2146 IsEmptyLayoutEntry(
2147 IN PPARTITION_INFORMATION PartitionInfo)
2148 {
2149 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2150 PartitionInfo->PartitionLength.QuadPart == 0)
2151 {
2152 return TRUE;
2153 }
2154
2155 return FALSE;
2156 }
2157
2158 // static
2159 FORCEINLINE
2160 BOOLEAN
2161 IsSamePrimaryLayoutEntry(
2162 IN PPARTITION_INFORMATION PartitionInfo,
2163 IN PDISKENTRY DiskEntry,
2164 IN PPARTENTRY PartEntry)
2165 {
2166 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2167 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2168 // PartitionInfo->PartitionType == PartEntry->PartitionType
2169 {
2170 return TRUE;
2171 }
2172
2173 return FALSE;
2174 }
2175
2176 static
2177 ULONG
2178 GetPrimaryPartitionCount(
2179 IN PDISKENTRY DiskEntry)
2180 {
2181 PLIST_ENTRY Entry;
2182 PPARTENTRY PartEntry;
2183 ULONG Count = 0;
2184
2185 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
2186 Entry != &DiskEntry->PrimaryPartListHead;
2187 Entry = Entry->Flink)
2188 {
2189 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2190 if (PartEntry->IsPartitioned)
2191 Count++;
2192 }
2193
2194 return Count;
2195 }
2196
2197 static
2198 ULONG
2199 GetLogicalPartitionCount(
2200 IN PDISKENTRY DiskEntry)
2201 {
2202 PLIST_ENTRY ListEntry;
2203 PPARTENTRY PartEntry;
2204 ULONG Count = 0;
2205
2206 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2207 ListEntry != &DiskEntry->LogicalPartListHead;
2208 ListEntry = ListEntry->Flink)
2209 {
2210 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2211 if (PartEntry->IsPartitioned)
2212 Count++;
2213 }
2214
2215 return Count;
2216 }
2217
2218 static
2219 BOOLEAN
2220 ReAllocateLayoutBuffer(
2221 IN PDISKENTRY DiskEntry)
2222 {
2223 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2224 ULONG NewPartitionCount;
2225 ULONG CurrentPartitionCount = 0;
2226 ULONG LayoutBufferSize;
2227 ULONG i;
2228
2229 DPRINT1("ReAllocateLayoutBuffer()\n");
2230
2231 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2232
2233 if (DiskEntry->LayoutBuffer)
2234 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2235
2236 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2237 CurrentPartitionCount, NewPartitionCount);
2238
2239 if (CurrentPartitionCount == NewPartitionCount)
2240 return TRUE;
2241
2242 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2243 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2244 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2245 HEAP_ZERO_MEMORY,
2246 DiskEntry->LayoutBuffer,
2247 LayoutBufferSize);
2248 if (NewLayoutBuffer == NULL)
2249 {
2250 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2251 return FALSE;
2252 }
2253
2254 NewLayoutBuffer->PartitionCount = NewPartitionCount;
2255
2256 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2257 if (NewPartitionCount > CurrentPartitionCount)
2258 {
2259 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2260 {
2261 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2262 }
2263 }
2264
2265 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2266
2267 return TRUE;
2268 }
2269
2270 static
2271 VOID
2272 UpdateDiskLayout(
2273 IN PDISKENTRY DiskEntry)
2274 {
2275 PPARTITION_INFORMATION PartitionInfo;
2276 PPARTITION_INFORMATION LinkInfo = NULL;
2277 PLIST_ENTRY ListEntry;
2278 PPARTENTRY PartEntry;
2279 LARGE_INTEGER HiddenSectors64;
2280 ULONG Index;
2281 ULONG PartitionNumber = 1;
2282
2283 DPRINT1("UpdateDiskLayout()\n");
2284
2285 /* Resize the layout buffer if necessary */
2286 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2287 {
2288 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2289 return;
2290 }
2291
2292 /* Update the primary partition table */
2293 Index = 0;
2294 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2295 ListEntry != &DiskEntry->PrimaryPartListHead;
2296 ListEntry = ListEntry->Flink)
2297 {
2298 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2299
2300 if (PartEntry->IsPartitioned)
2301 {
2302 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2303 PartEntry->PartitionIndex = Index;
2304
2305 /* Reset the current partition number only for newly-created partitions */
2306 if (PartEntry->New)
2307 PartEntry->PartitionNumber = 0;
2308
2309 PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2310
2311 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2312 {
2313 DPRINT1("Updating primary partition entry %lu\n", Index);
2314
2315 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2316 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2317 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2318 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2319 PartitionInfo->PartitionType = PartEntry->PartitionType;
2320 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2321 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2322 PartitionInfo->RewritePartition = TRUE;
2323 }
2324
2325 if (!IsContainerPartition(PartEntry->PartitionType))
2326 PartitionNumber++;
2327
2328 Index++;
2329 }
2330 }
2331
2332 ASSERT(Index <= 4);
2333
2334 /* Update the logical partition table */
2335 Index = 4;
2336 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2337 ListEntry != &DiskEntry->LogicalPartListHead;
2338 ListEntry = ListEntry->Flink)
2339 {
2340 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2341
2342 if (PartEntry->IsPartitioned)
2343 {
2344 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2345 PartEntry->PartitionIndex = Index;
2346
2347 DPRINT1("Updating logical partition entry %lu\n", Index);
2348
2349 /* Reset the current partition number only for newly-created partitions */
2350 if (PartEntry->New)
2351 PartEntry->PartitionNumber = 0;
2352
2353 PartEntry->OnDiskPartitionNumber = PartitionNumber;
2354
2355 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2356 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2357 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2358 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2359 PartitionInfo->PartitionType = PartEntry->PartitionType;
2360 PartitionInfo->BootIndicator = FALSE;
2361 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2362 PartitionInfo->RewritePartition = TRUE;
2363
2364 /* Fill the link entry of the previous partition entry */
2365 if (LinkInfo != NULL)
2366 {
2367 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2368 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2369 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2370 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2371 LinkInfo->PartitionNumber = 0;
2372 LinkInfo->PartitionType = PARTITION_EXTENDED;
2373 LinkInfo->BootIndicator = FALSE;
2374 LinkInfo->RecognizedPartition = FALSE;
2375 LinkInfo->RewritePartition = TRUE;
2376 }
2377
2378 /* Save a pointer to the link entry of the current partition entry */
2379 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2380
2381 PartitionNumber++;
2382 Index += 4;
2383 }
2384 }
2385
2386 /* Wipe unused primary partition entries */
2387 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2388 {
2389 DPRINT1("Primary partition entry %lu\n", Index);
2390
2391 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2392
2393 if (!IsEmptyLayoutEntry(PartitionInfo))
2394 {
2395 DPRINT1("Wiping primary partition entry %lu\n", Index);
2396
2397 PartitionInfo->StartingOffset.QuadPart = 0;
2398 PartitionInfo->PartitionLength.QuadPart = 0;
2399 PartitionInfo->HiddenSectors = 0;
2400 PartitionInfo->PartitionNumber = 0;
2401 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2402 PartitionInfo->BootIndicator = FALSE;
2403 PartitionInfo->RecognizedPartition = FALSE;
2404 PartitionInfo->RewritePartition = TRUE;
2405 }
2406 }
2407
2408 /* Wipe unused logical partition entries */
2409 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2410 {
2411 if (Index % 4 >= 2)
2412 {
2413 DPRINT1("Logical partition entry %lu\n", Index);
2414
2415 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2416
2417 if (!IsEmptyLayoutEntry(PartitionInfo))
2418 {
2419 DPRINT1("Wiping partition entry %lu\n", Index);
2420
2421 PartitionInfo->StartingOffset.QuadPart = 0;
2422 PartitionInfo->PartitionLength.QuadPart = 0;
2423 PartitionInfo->HiddenSectors = 0;
2424 PartitionInfo->PartitionNumber = 0;
2425 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2426 PartitionInfo->BootIndicator = FALSE;
2427 PartitionInfo->RecognizedPartition = FALSE;
2428 PartitionInfo->RewritePartition = TRUE;
2429 }
2430 }
2431 }
2432
2433 DiskEntry->Dirty = TRUE;
2434
2435 #ifdef DUMP_PARTITION_TABLE
2436 DumpPartitionTable(DiskEntry);
2437 #endif
2438 }
2439
2440 static
2441 PPARTENTRY
2442 GetPrevUnpartitionedEntry(
2443 IN PDISKENTRY DiskEntry,
2444 IN PPARTENTRY PartEntry)
2445 {
2446 PPARTENTRY PrevPartEntry;
2447 PLIST_ENTRY ListHead;
2448
2449 if (PartEntry->LogicalPartition)
2450 ListHead = &DiskEntry->LogicalPartListHead;
2451 else
2452 ListHead = &DiskEntry->PrimaryPartListHead;
2453
2454 if (PartEntry->ListEntry.Blink != ListHead)
2455 {
2456 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2457 PARTENTRY,
2458 ListEntry);
2459 if (PrevPartEntry->IsPartitioned == FALSE)
2460 return PrevPartEntry;
2461 }
2462
2463 return NULL;
2464 }
2465
2466 static
2467 PPARTENTRY
2468 GetNextUnpartitionedEntry(
2469 IN PDISKENTRY DiskEntry,
2470 IN PPARTENTRY PartEntry)
2471 {
2472 PPARTENTRY NextPartEntry;
2473 PLIST_ENTRY ListHead;
2474
2475 if (PartEntry->LogicalPartition)
2476 ListHead = &DiskEntry->LogicalPartListHead;
2477 else
2478 ListHead = &DiskEntry->PrimaryPartListHead;
2479
2480 if (PartEntry->ListEntry.Flink != ListHead)
2481 {
2482 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2483 PARTENTRY,
2484 ListEntry);
2485 if (NextPartEntry->IsPartitioned == FALSE)
2486 return NextPartEntry;
2487 }
2488
2489 return NULL;
2490 }
2491
2492 BOOLEAN
2493 CreatePrimaryPartition(
2494 IN PPARTLIST List,
2495 IN ULONGLONG SectorCount,
2496 IN BOOLEAN AutoCreate)
2497 {
2498 ERROR_NUMBER Error;
2499 PDISKENTRY DiskEntry;
2500 PPARTENTRY PartEntry;
2501
2502 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2503
2504 if (List == NULL ||
2505 List->CurrentDisk == NULL ||
2506 List->CurrentPartition == NULL ||
2507 List->CurrentPartition->IsPartitioned)
2508 {
2509 return FALSE;
2510 }
2511
2512 Error = PrimaryPartitionCreationChecks(List);
2513 if (Error != NOT_AN_ERROR)
2514 {
2515 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error);
2516 return FALSE;
2517 }
2518
2519 DiskEntry = List->CurrentDisk;
2520 PartEntry = List->CurrentPartition;
2521
2522 /* Convert the current entry, or insert and initialize a new partition entry */
2523 PartEntry = InitializePartitionEntry(DiskEntry, PartEntry, SectorCount, AutoCreate);
2524 if (PartEntry == NULL)
2525 return FALSE;
2526
2527 UpdateDiskLayout(DiskEntry);
2528
2529 AssignDriveLetters(List);
2530
2531 return TRUE;
2532 }
2533
2534 static
2535 VOID
2536 AddLogicalDiskSpace(
2537 IN PDISKENTRY DiskEntry)
2538 {
2539 ULONGLONG StartSector;
2540 ULONGLONG SectorCount;
2541 PPARTENTRY NewPartEntry;
2542
2543 DPRINT1("AddLogicalDiskSpace()\n");
2544
2545 /* Create a partition entry that represents the empty space in the container partition */
2546
2547 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2548 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2549
2550 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
2551 &DiskEntry->LogicalPartListHead,
2552 StartSector,
2553 SectorCount,
2554 TRUE);
2555 if (NewPartEntry == NULL)
2556 {
2557 DPRINT1("Failed to create a new empty region for extended partition space!\n");
2558 return;
2559 }
2560 NewPartEntry->LogicalPartition = TRUE;
2561 }
2562
2563 BOOLEAN
2564 CreateExtendedPartition(
2565 IN PPARTLIST List,
2566 IN ULONGLONG SectorCount)
2567 {
2568 ERROR_NUMBER Error;
2569 PDISKENTRY DiskEntry;
2570 PPARTENTRY PartEntry;
2571
2572 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2573
2574 if (List == NULL ||
2575 List->CurrentDisk == NULL ||
2576 List->CurrentPartition == NULL ||
2577 List->CurrentPartition->IsPartitioned)
2578 {
2579 return FALSE;
2580 }
2581
2582 Error = ExtendedPartitionCreationChecks(List);
2583 if (Error != NOT_AN_ERROR)
2584 {
2585 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error);
2586 return FALSE;
2587 }
2588
2589 DiskEntry = List->CurrentDisk;
2590 PartEntry = List->CurrentPartition;
2591
2592 /* Convert the current entry, or insert and initialize a new partition entry */
2593 PartEntry = InitializePartitionEntry(DiskEntry, PartEntry, SectorCount, FALSE);
2594 if (PartEntry == NULL)
2595 return FALSE;
2596
2597 if (PartEntry->StartSector.QuadPart < 1450560)
2598 {
2599 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2600 PartEntry->PartitionType = PARTITION_EXTENDED;
2601 }
2602 else
2603 {
2604 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2605 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2606 }
2607
2608 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2609 PartEntry->New = FALSE;
2610 PartEntry->FormatState = Formatted;
2611
2612 DiskEntry->ExtendedPartition = PartEntry;
2613
2614 AddLogicalDiskSpace(DiskEntry);
2615
2616 UpdateDiskLayout(DiskEntry);
2617
2618 AssignDriveLetters(List);
2619
2620 return TRUE;
2621 }
2622
2623 BOOLEAN
2624 CreateLogicalPartition(
2625 IN PPARTLIST List,
2626 IN ULONGLONG SectorCount,
2627 IN BOOLEAN AutoCreate)
2628 {
2629 ERROR_NUMBER Error;
2630 PDISKENTRY DiskEntry;
2631 PPARTENTRY PartEntry;
2632
2633 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2634
2635 if (List == NULL ||
2636 List->CurrentDisk == NULL ||
2637 List->CurrentPartition == NULL ||
2638 List->CurrentPartition->IsPartitioned)
2639 {
2640 return FALSE;
2641 }
2642
2643 Error = LogicalPartitionCreationChecks(List);
2644 if (Error != NOT_AN_ERROR)
2645 {
2646 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error);
2647 return FALSE;
2648 }
2649
2650 DiskEntry = List->CurrentDisk;
2651 PartEntry = List->CurrentPartition;
2652
2653 /* Convert the current entry, or insert and initialize a new partition entry */
2654 PartEntry = InitializePartitionEntry(DiskEntry, PartEntry, SectorCount, AutoCreate);
2655 if (PartEntry == NULL)
2656 return FALSE;
2657
2658 PartEntry->LogicalPartition = TRUE;
2659
2660 UpdateDiskLayout(DiskEntry);
2661
2662 AssignDriveLetters(List);
2663
2664 return TRUE;
2665 }
2666
2667 static
2668 NTSTATUS
2669 DismountVolume(
2670 IN PPARTENTRY PartEntry)
2671 {
2672 NTSTATUS Status;
2673 NTSTATUS LockStatus;
2674 UNICODE_STRING Name;
2675 OBJECT_ATTRIBUTES ObjectAttributes;
2676 IO_STATUS_BLOCK IoStatusBlock;
2677 HANDLE PartitionHandle;
2678 WCHAR Buffer[MAX_PATH];
2679
2680 /* Check whether the partition is valid and may have been mounted in the system */
2681 if (!PartEntry->IsPartitioned ||
2682 PartEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2683 IsContainerPartition(PartEntry->PartitionType) ||
2684 !IsRecognizedPartition(PartEntry->PartitionType) ||
2685 PartEntry->FormatState == Unformatted /* || PartEntry->FormatState == UnknownFormat */ ||
2686 PartEntry->FileSystem == NULL ||
2687 PartEntry->PartitionNumber == 0)
2688 {
2689 /* The partition is not mounted, so just return success */
2690 return STATUS_SUCCESS;
2691 }
2692
2693 /* Open the volume */
2694 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
2695 L"\\Device\\Harddisk%lu\\Partition%lu",
2696 PartEntry->DiskEntry->DiskNumber,
2697 PartEntry->PartitionNumber);
2698 RtlInitUnicodeString(&Name, Buffer);
2699
2700 InitializeObjectAttributes(&ObjectAttributes,
2701 &Name,
2702 OBJ_CASE_INSENSITIVE,
2703 NULL,
2704 NULL);
2705
2706 Status = NtOpenFile(&PartitionHandle,
2707 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2708 &ObjectAttributes,
2709 &IoStatusBlock,
2710 FILE_SHARE_READ | FILE_SHARE_WRITE,
2711 FILE_SYNCHRONOUS_IO_NONALERT);
2712 if (!NT_SUCCESS(Status))
2713 {
2714 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status);
2715 return Status;
2716 }
2717
2718 /* Lock the volume */
2719 LockStatus = NtFsControlFile(PartitionHandle,
2720 NULL,
2721 NULL,
2722 NULL,
2723 &IoStatusBlock,
2724 FSCTL_LOCK_VOLUME,
2725 NULL,
2726 0,
2727 NULL,
2728 0);
2729 if (!NT_SUCCESS(LockStatus))
2730 {
2731 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus);
2732 }
2733
2734 /* Dismount the volume */
2735 Status = NtFsControlFile(PartitionHandle,
2736 NULL,
2737 NULL,
2738 NULL,
2739 &IoStatusBlock,
2740 FSCTL_DISMOUNT_VOLUME,
2741 NULL,
2742 0,
2743 NULL,
2744 0);
2745 if (!NT_SUCCESS(Status))
2746 {
2747 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status);
2748 }
2749
2750 /* Unlock the volume */
2751 LockStatus = NtFsControlFile(PartitionHandle,
2752 NULL,
2753 NULL,
2754 NULL,
2755 &IoStatusBlock,
2756 FSCTL_UNLOCK_VOLUME,
2757 NULL,
2758 0,
2759 NULL,
2760 0);
2761 if (!NT_SUCCESS(LockStatus))
2762 {
2763 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus);
2764 }
2765
2766 /* Close the volume */
2767 NtClose(PartitionHandle);
2768
2769 return Status;
2770 }
2771
2772 VOID
2773 DeleteCurrentPartition(
2774 IN PPARTLIST List)
2775 {
2776 PDISKENTRY DiskEntry;
2777 PPARTENTRY PartEntry;
2778 PPARTENTRY PrevPartEntry;
2779 PPARTENTRY NextPartEntry;
2780 PPARTENTRY LogicalPartEntry;
2781 PLIST_ENTRY Entry;
2782
2783 if (List == NULL ||
2784 List->CurrentDisk == NULL ||
2785 List->CurrentPartition == NULL ||
2786 List->CurrentPartition->IsPartitioned == FALSE)
2787 {
2788 return;
2789 }
2790
2791 /* Clear the system disk and partition pointers if the system partition is being deleted */
2792 if (List->SystemPartition == List->CurrentPartition)
2793 {
2794 List->SystemPartition = NULL;
2795 }
2796
2797 DiskEntry = List->CurrentDisk;
2798 PartEntry = List->CurrentPartition;
2799
2800 /* Check which type of partition (primary/logical or extended) is being deleted */
2801 if (DiskEntry->ExtendedPartition == PartEntry)
2802 {
2803 /* An extended partition is being deleted: delete all logical partition entries */
2804 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2805 {
2806 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2807 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2808
2809 /* Dismount the logical partition */
2810 DismountVolume(LogicalPartEntry);
2811
2812 /* Delete it */
2813 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2814 }
2815
2816 DiskEntry->ExtendedPartition = NULL;
2817 }
2818 else
2819 {
2820 /* A primary partition is being deleted: dismount it */
2821 DismountVolume(PartEntry);
2822 }
2823
2824 /* Adjust unpartitioned disk space entries */
2825
2826 /* Get pointer to previous and next unpartitioned entries */
2827 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
2828 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
2829
2830 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2831 {
2832 /* Merge previous, current and next unpartitioned entry */
2833
2834 /* Adjust the previous entries length */
2835 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2836
2837 /* Remove the current entry */
2838 RemoveEntryList(&PartEntry->ListEntry);
2839 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2840
2841 /* Remove the next entry */
2842 RemoveEntryList(&NextPartEntry->ListEntry);
2843 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2844
2845 /* Update current partition */
2846 List->CurrentPartition = PrevPartEntry;
2847 }
2848 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2849 {
2850 /* Merge current and previous unpartitioned entry */
2851
2852 /* Adjust the previous entries length */
2853 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2854
2855 /* Remove the current entry */
2856 RemoveEntryList(&PartEntry->ListEntry);
2857 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2858
2859 /* Update current partition */
2860 List->CurrentPartition = PrevPartEntry;
2861 }
2862 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2863 {
2864 /* Merge current and next unpartitioned entry */
2865
2866 /* Adjust the next entries offset and length */
2867 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2868 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2869
2870 /* Remove the current entry */
2871 RemoveEntryList(&PartEntry->ListEntry);
2872 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2873
2874 /* Update current partition */
2875 List->CurrentPartition = NextPartEntry;
2876 }
2877 else
2878 {
2879 /* Nothing to merge but change current entry */
2880 PartEntry->IsPartitioned = FALSE;
2881 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2882 PartEntry->FormatState = Unformatted;
2883 PartEntry->FileSystem = NULL;
2884 PartEntry->DriveLetter = 0;
2885 PartEntry->OnDiskPartitionNumber = 0;
2886 PartEntry->PartitionNumber = 0;
2887 // PartEntry->PartitionIndex = 0;
2888 }
2889
2890 UpdateDiskLayout(DiskEntry);
2891
2892 AssignDriveLetters(List);
2893 }
2894
2895 VOID
2896 CheckActiveSystemPartition(
2897 IN PPARTLIST List)
2898 {
2899 PDISKENTRY DiskEntry;
2900 PPARTENTRY PartEntry;
2901 PLIST_ENTRY ListEntry;
2902
2903 PFILE_SYSTEM FileSystem;
2904
2905 /* Check for empty disk list */
2906 if (IsListEmpty(&List->DiskListHead))
2907 {
2908 List->SystemPartition = NULL;
2909 List->OriginalSystemPartition = NULL;
2910 return;
2911 }
2912
2913 /* Choose the currently selected disk */
2914 DiskEntry = List->CurrentDisk;
2915
2916 /* Check for empty partition list */
2917 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
2918 {
2919 List->SystemPartition = NULL;
2920 List->OriginalSystemPartition = NULL;
2921 return;
2922 }
2923
2924 if (List->SystemPartition != NULL)
2925 {
2926 /* We already have an active system partition */
2927 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
2928 List->SystemPartition->PartitionNumber,
2929 List->SystemPartition->DiskEntry->DiskNumber,
2930 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2931 return;
2932 }
2933
2934 DPRINT1("We are here (1)!\n");
2935
2936 List->SystemPartition = NULL;
2937 List->OriginalSystemPartition = NULL;
2938
2939 /* Retrieve the first partition of the disk */
2940 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2941 PARTENTRY,
2942 ListEntry);
2943 ASSERT(DiskEntry == PartEntry->DiskEntry);
2944 List->SystemPartition = PartEntry;
2945
2946 //
2947 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
2948 //
2949
2950 /* Check if the disk is new and if so, use its first partition as the active system partition */
2951 if (DiskEntry->NewDisk)
2952 {
2953 if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator == FALSE)
2954 {
2955 ASSERT(DiskEntry == PartEntry->DiskEntry);
2956 List->SystemPartition = PartEntry;
2957
2958 List->OriginalSystemPartition = List->SystemPartition;
2959
2960 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
2961 List->SystemPartition->PartitionNumber,
2962 List->SystemPartition->DiskEntry->DiskNumber,
2963 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2964
2965 goto SetSystemPartition;
2966 }
2967
2968 // FIXME: What to do??
2969 DPRINT1("NewDisk TRUE but first partition is used?\n");
2970 }
2971
2972 DPRINT1("We are here (2)!\n");
2973
2974 /*
2975 * The disk is not new, check if any partition is initialized;
2976 * if not, the first one becomes the system partition.
2977 */
2978 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2979 ListEntry != &DiskEntry->PrimaryPartListHead;
2980 ListEntry = ListEntry->Flink)
2981 {
2982 /* Retrieve the partition */
2983 PartEntry = CONTAINING_RECORD(ListEntry,
2984 PARTENTRY,
2985 ListEntry);
2986
2987 /* Check if the partition is partitioned and is used */
2988 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
2989 {
2990 break;
2991 }
2992 }
2993 if (ListEntry == &DiskEntry->PrimaryPartListHead)
2994 {
2995 /*
2996 * OK we haven't encountered any used and active partition,
2997 * so use the first one as the system partition.
2998 */
2999 ASSERT(DiskEntry == List->SystemPartition->DiskEntry);
3000 List->OriginalSystemPartition = List->SystemPartition; // First PartEntry
3001
3002 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3003 List->SystemPartition->PartitionNumber,
3004 List->SystemPartition->DiskEntry->DiskNumber,
3005 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3006
3007 goto SetSystemPartition;
3008 }
3009
3010 List->SystemPartition = NULL;
3011 List->OriginalSystemPartition = NULL;
3012
3013 DPRINT1("We are here (3)!\n");
3014
3015 /* The disk is not new, scan all partitions to find the (active) system partition */
3016 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3017 ListEntry != &DiskEntry->PrimaryPartListHead;
3018 ListEntry = ListEntry->Flink)
3019 {
3020 /* Retrieve the partition */
3021 PartEntry = CONTAINING_RECORD(ListEntry,
3022 PARTENTRY,
3023 ListEntry);
3024
3025 /* Check if the partition is partitioned and used */
3026 if (PartEntry->IsPartitioned &&
3027 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
3028 {
3029 /* Check if the partition is active */
3030 if (PartEntry->BootIndicator)
3031 {
3032 /* Yes, we found it */
3033 ASSERT(DiskEntry == PartEntry->DiskEntry);
3034 List->SystemPartition = PartEntry;
3035
3036 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
3037 PartEntry->PartitionNumber,
3038 DiskEntry->DiskNumber,
3039 (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter);
3040 break;
3041 }
3042 }
3043 }
3044
3045 /* Check if we have found the system partition */
3046 if (List->SystemPartition == NULL)
3047 {
3048 /* Nothing, use the alternative system partition */
3049 DPRINT1("No system partition found, use the alternative partition!\n");
3050 goto UseAlternativeSystemPartition;
3051 }
3052
3053 /* Save it */
3054 List->OriginalSystemPartition = List->SystemPartition;
3055
3056 /*
3057 * ADDITIONAL CHECKS / BIG HACK:
3058 *
3059 * Retrieve its file system and check whether we have
3060 * write support for it. If that is the case we are fine
3061 * and we can use it directly. However if we don't have
3062 * write support we will need to change the active system
3063 * partition.
3064 *
3065 * NOTE that this is completely useless on architectures
3066 * where a real system partition is required, as on these
3067 * architectures the partition uses the FAT FS, for which
3068 * we do have write support.
3069 * NOTE also that for those architectures looking for a
3070 * partition boot indicator is insufficient.
3071 */
3072 FileSystem = GetFileSystem(List->OriginalSystemPartition);
3073 if (FileSystem == NULL)
3074 {
3075 DPRINT1("System partition %lu in disk %lu with no FS?!\n",
3076 List->OriginalSystemPartition->PartitionNumber,
3077 List->OriginalSystemPartition->DiskEntry->DiskNumber);
3078 goto FindAndUseAlternativeSystemPartition;
3079 }
3080 // HACK: WARNING: We cannot write on this FS yet!
3081 // See fsutil.c:GetFileSystem()
3082 if (List->OriginalSystemPartition->PartitionType == PARTITION_IFS)
3083 {
3084 DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
3085 FileSystem->FileSystemName);
3086 goto FindAndUseAlternativeSystemPartition;
3087 }
3088
3089 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
3090 List->SystemPartition->PartitionNumber,
3091 List->SystemPartition->DiskEntry->DiskNumber,
3092 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3093
3094 return;
3095
3096 FindAndUseAlternativeSystemPartition:
3097 /*
3098 * We are here because we have not found any (active) candidate
3099 * system partition that we know how to support. What we are going
3100 * to do is to change the existing system partition and use the
3101 * partition on which we install ReactOS as the new system partition,
3102 * and then we will need to add in FreeLdr's entry a boot entry to boot
3103 * from the original system partition.
3104 */
3105
3106 /* Unset the old system partition */
3107 List->SystemPartition->BootIndicator = FALSE;
3108 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = FALSE;
3109 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3110 List->SystemPartition->DiskEntry->Dirty = TRUE;
3111
3112 UseAlternativeSystemPartition:
3113 List->SystemPartition = List->CurrentPartition;
3114
3115 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3116 List->SystemPartition->PartitionNumber,
3117 List->SystemPartition->DiskEntry->DiskNumber,
3118 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3119
3120 SetSystemPartition:
3121 /* Set the new active system partition */
3122 List->SystemPartition->BootIndicator = TRUE;
3123 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = TRUE;
3124 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3125 List->SystemPartition->DiskEntry->Dirty = TRUE;
3126 }
3127
3128 static
3129 NTSTATUS
3130 WritePartitions(
3131 IN PPARTLIST List,
3132 IN PDISKENTRY DiskEntry)
3133 {
3134 NTSTATUS Status;
3135 OBJECT_ATTRIBUTES ObjectAttributes;
3136 UNICODE_STRING Name;
3137 HANDLE FileHandle;
3138 IO_STATUS_BLOCK Iosb;
3139 ULONG BufferSize;
3140 PPARTITION_INFORMATION PartitionInfo;
3141 ULONG PartitionCount;
3142 PLIST_ENTRY ListEntry;
3143 PPARTENTRY PartEntry;
3144 WCHAR DstPath[MAX_PATH];
3145
3146 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3147
3148 RtlStringCchPrintfW(DstPath, ARRAYSIZE(DstPath),
3149 L"\\Device\\Harddisk%lu\\Partition0",
3150 DiskEntry->DiskNumber);
3151 RtlInitUnicodeString(&Name, DstPath);
3152
3153 InitializeObjectAttributes(&ObjectAttributes,
3154 &Name,
3155 OBJ_CASE_INSENSITIVE,
3156 NULL,
3157 NULL);
3158
3159 Status = NtOpenFile(&FileHandle,
3160 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3161 &ObjectAttributes,
3162 &Iosb,
3163 0,
3164 FILE_SYNCHRONOUS_IO_NONALERT);
3165 if (!NT_SUCCESS(Status))
3166 {
3167 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3168 return Status;
3169 }
3170
3171 #ifdef DUMP_PARTITION_TABLE
3172 DumpPartitionTable(DiskEntry);
3173 #endif
3174
3175 //
3176 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3177 // the disk in MBR or GPT format in case the disk was not initialized!!
3178 // For this we must ask the user which format to use.
3179 //
3180
3181 /* Save the original partition count to be restored later (see comment below) */
3182 PartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
3183
3184 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
3185 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
3186 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3187 Status = NtDeviceIoControlFile(FileHandle,
3188 NULL,
3189 NULL,
3190 NULL,
3191 &Iosb,
3192 IOCTL_DISK_SET_DRIVE_LAYOUT,
3193 DiskEntry->LayoutBuffer,
3194 BufferSize,
3195 DiskEntry->LayoutBuffer,
3196 BufferSize);
3197 NtClose(FileHandle);
3198
3199 /*
3200 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3201 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3202 * where such a table is expected to enumerate up to 4 partitions:
3203 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3204 * Due to this we need to restore the original PartitionCount number.
3205 */
3206 DiskEntry->LayoutBuffer->PartitionCount = PartitionCount;
3207
3208 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3209 if (!NT_SUCCESS(Status))
3210 {
3211 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3212 return Status;
3213 }
3214
3215 #ifdef DUMP_PARTITION_TABLE
3216 DumpPartitionTable(DiskEntry);
3217 #endif
3218
3219 /* Update the partition numbers */
3220
3221 /* Update the primary partition table */
3222 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3223 ListEntry != &DiskEntry->PrimaryPartListHead;
3224 ListEntry = ListEntry->Flink)
3225 {
3226 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3227
3228 if (PartEntry->IsPartitioned)
3229 {
3230 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3231 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3232 }
3233 }
3234
3235 /* Update the logical partition table */
3236 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
3237 ListEntry != &DiskEntry->LogicalPartListHead;
3238 ListEntry = ListEntry->Flink)
3239 {
3240 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3241
3242 if (PartEntry->IsPartitioned)
3243 {
3244 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3245 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3246 }
3247 }
3248
3249 //
3250 // NOTE: Originally (see r40437), we used to install here also a new MBR
3251 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3252 // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
3253 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3254 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3255 // was called too, the installation test was modified by checking whether
3256 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3257 //
3258
3259 // DiskEntry->Dirty = FALSE;
3260
3261 return Status;
3262 }
3263
3264 BOOLEAN
3265 WritePartitionsToDisk(
3266 IN PPARTLIST List)
3267 {
3268 PLIST_ENTRY Entry;
3269 PDISKENTRY DiskEntry;
3270
3271 if (List == NULL)
3272 return TRUE;
3273
3274 for (Entry = List->DiskListHead.Flink;
3275 Entry != &List->DiskListHead;
3276 Entry = Entry->Flink)
3277 {
3278 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3279
3280 if (DiskEntry->Dirty != FALSE)
3281 {
3282 WritePartitions(List, DiskEntry);
3283 DiskEntry->Dirty = FALSE;
3284 }
3285 }
3286
3287 return TRUE;
3288 }
3289
3290 BOOLEAN
3291 SetMountedDeviceValue(
3292 IN WCHAR Letter,
3293 IN ULONG Signature,
3294 IN LARGE_INTEGER StartingOffset)
3295 {
3296 OBJECT_ATTRIBUTES ObjectAttributes;
3297 WCHAR ValueNameBuffer[16];
3298 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3299 UNICODE_STRING ValueName;
3300 REG_DISK_MOUNT_INFO MountInfo;
3301 NTSTATUS Status;
3302 HANDLE KeyHandle;
3303
3304 RtlStringCchPrintfW(ValueNameBuffer, ARRAYSIZE(ValueNameBuffer),
3305 L"\\DosDevices\\%c:", Letter);
3306 RtlInitUnicodeString(&ValueName, ValueNameBuffer);
3307
3308 InitializeObjectAttributes(&ObjectAttributes,
3309 &KeyName,
3310 OBJ_CASE_INSENSITIVE,
3311 NULL,
3312 NULL);
3313
3314 Status = NtOpenKey(&KeyHandle,
3315 KEY_ALL_ACCESS,
3316 &ObjectAttributes);
3317 if (!NT_SUCCESS(Status))
3318 {
3319 Status = NtCreateKey(&KeyHandle,
3320 KEY_ALL_ACCESS,
3321 &ObjectAttributes,
3322 0,
3323 NULL,
3324 REG_OPTION_NON_VOLATILE,
3325 NULL);
3326 }
3327
3328 if (!NT_SUCCESS(Status))
3329 {
3330 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
3331 return FALSE;
3332 }
3333
3334 MountInfo.Signature = Signature;
3335 MountInfo.StartingOffset = StartingOffset;
3336 Status = NtSetValueKey(KeyHandle,
3337 &ValueName,
3338 0,
3339 REG_BINARY,
3340 (PVOID)&MountInfo,
3341 sizeof(MountInfo));
3342 NtClose(KeyHandle);
3343 if (!NT_SUCCESS(Status))
3344 {
3345 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
3346 return FALSE;
3347 }
3348
3349 return TRUE;
3350 }
3351
3352 BOOLEAN
3353 SetMountedDeviceValues(
3354 IN PPARTLIST List)
3355 {
3356 PLIST_ENTRY Entry1, Entry2;
3357 PDISKENTRY DiskEntry;
3358 PPARTENTRY PartEntry;
3359 LARGE_INTEGER StartingOffset;
3360
3361 if (List == NULL)
3362 return FALSE;
3363
3364 for (Entry1 = List->DiskListHead.Flink;
3365 Entry1 != &List->DiskListHead;
3366 Entry1 = Entry1->Flink)
3367 {
3368 DiskEntry = CONTAINING_RECORD(Entry1,
3369 DISKENTRY,
3370 ListEntry);
3371
3372 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3373 Entry2 != &DiskEntry->PrimaryPartListHead;
3374 Entry2 = Entry2->Flink)
3375 {
3376 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3377 if (PartEntry->IsPartitioned)
3378 {
3379 /* Assign a "\DosDevices\#:" mount point to this partition */
3380 if (PartEntry->DriveLetter)
3381 {
3382 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3383 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3384 DiskEntry->LayoutBuffer->Signature,
3385 StartingOffset))
3386 {
3387 return FALSE;
3388 }
3389 }
3390 }
3391 }
3392
3393 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
3394 Entry2 != &DiskEntry->LogicalPartListHead;
3395 Entry2 = Entry2->Flink)
3396 {
3397 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3398 if (PartEntry->IsPartitioned)
3399 {
3400 /* Assign a "\DosDevices\#:" mount point to this partition */
3401 if (PartEntry->DriveLetter)
3402 {
3403 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3404 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3405 DiskEntry->LayoutBuffer->Signature,
3406 StartingOffset))
3407 {
3408 return FALSE;
3409 }
3410 }
3411 }
3412 }
3413 }
3414
3415 return TRUE;
3416 }
3417
3418 VOID
3419 SetPartitionType(
3420 IN PPARTENTRY PartEntry,
3421 IN UCHAR PartitionType)
3422 {
3423 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
3424
3425 PartEntry->PartitionType = PartitionType;
3426
3427 DiskEntry->Dirty = TRUE;
3428 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
3429 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RecognizedPartition = IsRecognizedPartition(PartitionType);
3430 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3431 }
3432
3433 ERROR_NUMBER
3434 PrimaryPartitionCreationChecks(
3435 IN PPARTLIST List)
3436 {
3437 PDISKENTRY DiskEntry;
3438 PPARTENTRY PartEntry;
3439
3440 DiskEntry = List->CurrentDisk;
3441 PartEntry = List->CurrentPartition;
3442
3443 /* Fail if the partition is already in use */
3444 if (PartEntry->IsPartitioned)
3445 return ERROR_NEW_PARTITION;
3446
3447 /* Fail if there are already 4 primary partitions in the list */
3448 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3449 return ERROR_PARTITION_TABLE_FULL;
3450
3451 return ERROR_SUCCESS;
3452 }
3453
3454 ERROR_NUMBER
3455 ExtendedPartitionCreationChecks(
3456 IN PPARTLIST List)
3457 {
3458 PDISKENTRY DiskEntry;
3459 PPARTENTRY PartEntry;
3460
3461 DiskEntry = List->CurrentDisk;
3462 PartEntry = List->CurrentPartition;
3463
3464 /* Fail if the partition is already in use */
3465 if (PartEntry->IsPartitioned)
3466 return ERROR_NEW_PARTITION;
3467
3468 /* Fail if there are already 4 primary partitions in the list */
3469 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3470 return ERROR_PARTITION_TABLE_FULL;
3471
3472 /* Fail if there is another extended partition in the list */
3473 if (DiskEntry->ExtendedPartition != NULL)
3474 return ERROR_ONLY_ONE_EXTENDED;
3475
3476 return ERROR_SUCCESS;
3477 }
3478
3479 ERROR_NUMBER
3480 LogicalPartitionCreationChecks(
3481 IN PPARTLIST List)
3482 {
3483 // PDISKENTRY DiskEntry;
3484 PPARTENTRY PartEntry;
3485
3486 // DiskEntry = List->CurrentDisk;
3487 PartEntry = List->CurrentPartition;
3488
3489 /* Fail if the partition is already in use */
3490 if (PartEntry->IsPartitioned)
3491 return ERROR_NEW_PARTITION;
3492
3493 return ERROR_SUCCESS;
3494 }
3495
3496 BOOLEAN
3497 GetNextUnformattedPartition(
3498 IN PPARTLIST List,
3499 OUT PDISKENTRY *pDiskEntry OPTIONAL,
3500 OUT PPARTENTRY *pPartEntry)
3501 {
3502 PLIST_ENTRY Entry1, Entry2;
3503 PDISKENTRY DiskEntry;
3504 PPARTENTRY PartEntry;
3505
3506 for (Entry1 = List->DiskListHead.Flink;
3507 Entry1 != &List->DiskListHead;
3508 Entry1 = Entry1->Flink)
3509 {
3510 DiskEntry = CONTAINING_RECORD(Entry1,
3511 DISKENTRY,
3512 ListEntry);
3513
3514 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3515 Entry2 != &DiskEntry->PrimaryPartListHead;
3516 Entry2 = Entry2->Flink)
3517 {
3518 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3519 if (PartEntry->IsPartitioned && PartEntry->New)
3520 {
3521 ASSERT(DiskEntry == PartEntry->DiskEntry);
3522 if (pDiskEntry) *pDiskEntry = DiskEntry;
3523 *pPartEntry = PartEntry;
3524 return TRUE;
3525 }
3526 }
3527
3528 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
3529 Entry2 != &DiskEntry->LogicalPartListHead;
3530 Entry2 = Entry2->Flink)
3531 {
3532 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3533 if (PartEntry->IsPartitioned && PartEntry->New)
3534 {
3535 ASSERT(DiskEntry == PartEntry->DiskEntry);
3536 if (pDiskEntry) *pDiskEntry = DiskEntry;
3537 *pPartEntry = PartEntry;
3538 return TRUE;
3539 }
3540 }
3541 }
3542
3543 if (pDiskEntry) *pDiskEntry = NULL;
3544 *pPartEntry = NULL;
3545
3546 return FALSE;
3547 }
3548
3549 BOOLEAN
3550 GetNextUncheckedPartition(
3551 IN PPARTLIST List,
3552 OUT PDISKENTRY *pDiskEntry OPTIONAL,
3553 OUT PPARTENTRY *pPartEntry)
3554 {
3555 PLIST_ENTRY Entry1, Entry2;
3556 PDISKENTRY DiskEntry;
3557 PPARTENTRY PartEntry;
3558
3559 for (Entry1 = List->DiskListHead.Flink;
3560 Entry1 != &List->DiskListHead;
3561 Entry1 = Entry1->Flink)
3562 {
3563 DiskEntry = CONTAINING_RECORD(Entry1,
3564 DISKENTRY,
3565 ListEntry);
3566
3567 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3568 Entry2 != &DiskEntry->PrimaryPartListHead;
3569 Entry2 = Entry2->Flink)
3570 {
3571 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3572 if (PartEntry->NeedsCheck == TRUE)
3573 {
3574 ASSERT(DiskEntry == PartEntry->DiskEntry);
3575 if (pDiskEntry) *pDiskEntry = DiskEntry;
3576 *pPartEntry = PartEntry;
3577 return TRUE;
3578 }
3579 }
3580
3581 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
3582 Entry2 != &DiskEntry->LogicalPartListHead;
3583 Entry2 = Entry2->Flink)
3584 {
3585 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3586 if (PartEntry->NeedsCheck == TRUE)
3587 {
3588 ASSERT(DiskEntry == PartEntry->DiskEntry);
3589 if (pDiskEntry) *pDiskEntry = DiskEntry;
3590 *pPartEntry = PartEntry;
3591 return TRUE;
3592 }
3593 }
3594 }
3595
3596 if (pDiskEntry) *pDiskEntry = NULL;
3597 *pPartEntry = NULL;
3598
3599 return FALSE;
3600 }
3601
3602 /* EOF */