The real, definitive, Visual C++ support branch. Accept no substitutes
[reactos.git] / base / setup / usetup / partlist.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004, 2005 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: subsys/system/usetup/partlist.c
22 * PURPOSE: Partition list functions
23 * PROGRAMMER: Eric Kohl
24 * Casper S. Hornstrup (chorns@users.sourceforge.net)
25 */
26
27 #include "usetup.h"
28
29 #define NDEBUG
30 #include <debug.h>
31
32 /* FUNCTIONS ****************************************************************/
33
34 static VOID
35 GetDriverName (PDISKENTRY DiskEntry)
36 {
37 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
38 WCHAR KeyName[32];
39 NTSTATUS Status;
40
41 RtlInitUnicodeString (&DiskEntry->DriverName,
42 NULL);
43
44 swprintf (KeyName,
45 L"\\Scsi\\Scsi Port %lu",
46 DiskEntry->Port);
47
48 RtlZeroMemory (&QueryTable,
49 sizeof(QueryTable));
50
51 QueryTable[0].Name = L"Driver";
52 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
53 QueryTable[0].EntryContext = &DiskEntry->DriverName;
54
55 Status = RtlQueryRegistryValues (RTL_REGISTRY_DEVICEMAP,
56 KeyName,
57 QueryTable,
58 NULL,
59 NULL);
60 if (!NT_SUCCESS (Status))
61 {
62 DPRINT1 ("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
63 }
64 }
65
66
67 static VOID
68 AssignDriverLetters (PPARTLIST List)
69 {
70 PDISKENTRY DiskEntry;
71 PPARTENTRY PartEntry;
72 PLIST_ENTRY Entry1;
73 PLIST_ENTRY Entry2;
74 CHAR Letter;
75
76 Letter = 'C';
77
78 /* Assign drive letters to primary partitions */
79 Entry1 = List->DiskListHead.Flink;
80 while (Entry1 != &List->DiskListHead)
81 {
82 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
83
84 if (!IsListEmpty (&DiskEntry->PartListHead))
85 {
86 PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
87 PARTENTRY,
88 ListEntry);
89
90 PartEntry->DriveLetter = 0;
91
92 if (PartEntry->Unpartitioned == FALSE &&
93 !IsContainerPartition (PartEntry->PartInfo[0].PartitionType))
94 {
95 if (IsRecognizedPartition (PartEntry->PartInfo[0].PartitionType) ||
96 (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED &&
97 PartEntry->PartInfo[0].PartitionLength.QuadPart != 0LL))
98 {
99 if (Letter <= 'Z')
100 {
101 PartEntry->DriveLetter = Letter;
102 Letter++;
103 }
104 }
105 }
106 }
107
108 Entry1 = Entry1->Flink;
109 }
110
111
112 /* Assign drive letters to logical drives */
113 Entry1 = List->DiskListHead.Flink;
114 while (Entry1 != &List->DiskListHead)
115 {
116 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
117
118 Entry2 = DiskEntry->PartListHead.Flink;
119 if (Entry2 != &DiskEntry->PartListHead)
120 {
121 Entry2 = Entry2->Flink;
122 while (Entry2 != &DiskEntry->PartListHead)
123 {
124 PartEntry = CONTAINING_RECORD (Entry2,
125 PARTENTRY,
126 ListEntry);
127
128 PartEntry->DriveLetter = 0;
129
130 if (PartEntry->Unpartitioned == FALSE &&
131 !IsContainerPartition (PartEntry->PartInfo[0].PartitionType))
132 {
133 if (IsRecognizedPartition (PartEntry->PartInfo[0].PartitionType) ||
134 (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED &&
135 PartEntry->PartInfo[0].PartitionLength.QuadPart != 0LL))
136 {
137 if (Letter <= 'Z')
138 {
139 PartEntry->DriveLetter = Letter;
140 Letter++;
141 }
142 }
143 }
144
145 Entry2 = Entry2->Flink;
146 }
147 }
148
149 Entry1 = Entry1->Flink;
150 }
151 }
152
153
154 static VOID
155 UpdatePartitionNumbers (PDISKENTRY DiskEntry)
156 {
157 PPARTENTRY PartEntry;
158 PLIST_ENTRY Entry;
159 ULONG PartNumber;
160 ULONG i;
161
162 PartNumber = 1;
163 Entry = DiskEntry->PartListHead.Flink;
164 while (Entry != &DiskEntry->PartListHead)
165 {
166 PartEntry = CONTAINING_RECORD (Entry,
167 PARTENTRY,
168 ListEntry);
169
170 if (PartEntry->Unpartitioned == TRUE)
171 {
172 for (i = 0; i < 4; i++)
173 {
174 PartEntry->PartInfo[i].PartitionNumber = 0;
175 }
176 }
177 else
178 {
179 for (i = 0; i < 4; i++)
180 {
181 if (IsContainerPartition (PartEntry->PartInfo[i].PartitionType))
182 {
183 PartEntry->PartInfo[i].PartitionNumber = 0;
184 }
185 else if (PartEntry->PartInfo[i].PartitionType == PARTITION_ENTRY_UNUSED &&
186 PartEntry->PartInfo[i].PartitionLength.QuadPart == 0ULL)
187 {
188 PartEntry->PartInfo[i].PartitionNumber = 0;
189 }
190 else
191 {
192 PartEntry->PartInfo[i].PartitionNumber = PartNumber;
193 PartNumber++;
194 }
195 }
196 }
197
198 Entry = Entry->Flink;
199 }
200 }
201
202
203 static VOID
204 AddPartitionToList (ULONG DiskNumber,
205 PDISKENTRY DiskEntry,
206 DRIVE_LAYOUT_INFORMATION *LayoutBuffer)
207 {
208 PPARTENTRY PartEntry;
209 ULONG i;
210 ULONG j;
211
212 for (i = 0; i < LayoutBuffer->PartitionCount; i += 4)
213 {
214 for (j = 0; j < 4; j++)
215 {
216 if (LayoutBuffer->PartitionEntry[i+j].PartitionType != PARTITION_ENTRY_UNUSED ||
217 LayoutBuffer->PartitionEntry[i+j].PartitionLength.QuadPart != 0ULL)
218 {
219 break;
220 }
221 }
222 if (j >= 4)
223 {
224 continue;
225 }
226
227 PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
228 0,
229 sizeof(PARTENTRY));
230 if (PartEntry == NULL)
231 {
232 return;
233 }
234
235 RtlZeroMemory (PartEntry,
236 sizeof(PARTENTRY));
237
238 PartEntry->Unpartitioned = FALSE;
239
240 for (j = 0; j < 4; j++)
241 {
242 RtlCopyMemory (&PartEntry->PartInfo[j],
243 &LayoutBuffer->PartitionEntry[i+j],
244 sizeof(PARTITION_INFORMATION));
245 }
246
247 if (IsContainerPartition(PartEntry->PartInfo[0].PartitionType))
248 {
249 PartEntry->FormatState = Unformatted;
250 }
251 else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
252 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
253 (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
254 (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13) ||
255 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
256 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
257 {
258 #if 0
259 if (CheckFatFormat())
260 {
261 PartEntry->FormatState = Preformatted;
262 }
263 else
264 {
265 PartEntry->FormatState = Unformatted;
266 }
267 #endif
268 PartEntry->FormatState = Preformatted;
269 }
270 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_EXT2)
271 {
272 #if 0
273 if (CheckExt2Format())
274 {
275 PartEntry->FormatState = Preformatted;
276 }
277 else
278 {
279 PartEntry->FormatState = Unformatted;
280 }
281 #endif
282 PartEntry->FormatState = Preformatted;
283 }
284 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
285 {
286 #if 0
287 if (CheckNtfsFormat())
288 {
289 PartEntry->FormatState = Preformatted;
290 }
291 else if (CheckHpfsFormat())
292 {
293 PartEntry->FormatState = Preformatted;
294 }
295 else
296 {
297 PartEntry->FormatState = Unformatted;
298 }
299 #endif
300 PartEntry->FormatState = Preformatted;
301 }
302 else
303 {
304 PartEntry->FormatState = UnknownFormat;
305 }
306
307 InsertTailList (&DiskEntry->PartListHead,
308 &PartEntry->ListEntry);
309 }
310 }
311
312
313 static VOID
314 ScanForUnpartitionedDiskSpace (PDISKENTRY DiskEntry)
315 {
316 ULONGLONG LastStartingOffset;
317 ULONGLONG LastPartitionLength;
318 ULONGLONG LastUnusedPartitionLength;
319 PPARTENTRY PartEntry;
320 PPARTENTRY NewPartEntry;
321 PLIST_ENTRY Entry;
322 ULONG i;
323 ULONG j;
324
325 if (IsListEmpty (&DiskEntry->PartListHead))
326 {
327 /* Create a partition table that represents the empty disk */
328 PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
329 0,
330 sizeof(PARTENTRY));
331 if (PartEntry == NULL)
332 return;
333
334 RtlZeroMemory (PartEntry,
335 sizeof(PARTENTRY));
336
337 PartEntry->Unpartitioned = TRUE;
338 PartEntry->UnpartitionedOffset = 0ULL;
339 PartEntry->UnpartitionedLength = DiskEntry->DiskSize;
340
341 PartEntry->FormatState = Unformatted;
342
343 InsertTailList (&DiskEntry->PartListHead,
344 &PartEntry->ListEntry);
345 }
346 else
347 {
348 /* Start partition at head 1, cylinder 0 */
349 LastStartingOffset = DiskEntry->TrackSize;
350 LastPartitionLength = 0ULL;
351 LastUnusedPartitionLength = 0ULL;
352
353 i = 0;
354 Entry = DiskEntry->PartListHead.Flink;
355 while (Entry != &DiskEntry->PartListHead)
356 {
357 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
358
359 for (j = 0; j < 4; j++)
360 {
361 if ((!IsContainerPartition (PartEntry->PartInfo[j].PartitionType)) &&
362 (PartEntry->PartInfo[j].PartitionType != PARTITION_ENTRY_UNUSED ||
363 PartEntry->PartInfo[j].PartitionLength.QuadPart != 0LL))
364 {
365 LastUnusedPartitionLength =
366 PartEntry->PartInfo[j].StartingOffset.QuadPart -
367 (LastStartingOffset + LastPartitionLength);
368
369 if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
370 {
371 DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
372
373 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
374 0,
375 sizeof(PARTENTRY));
376 if (NewPartEntry == NULL)
377 return;
378
379 RtlZeroMemory (NewPartEntry,
380 sizeof(PARTENTRY));
381
382 NewPartEntry->Unpartitioned = TRUE;
383 NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
384 NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
385 if (j == 0)
386 NewPartEntry->UnpartitionedLength -= DiskEntry->TrackSize;
387
388 NewPartEntry->FormatState = Unformatted;
389
390 /* Insert the table into the list */
391 InsertTailList (&PartEntry->ListEntry,
392 &NewPartEntry->ListEntry);
393 }
394
395 LastStartingOffset = PartEntry->PartInfo[j].StartingOffset.QuadPart;
396 LastPartitionLength = PartEntry->PartInfo[j].PartitionLength.QuadPart;
397 }
398 }
399
400 i += 4;
401 Entry = Entry->Flink;
402 }
403
404 /* Check for trailing unpartitioned disk space */
405 if (DiskEntry->DiskSize > (LastStartingOffset + LastPartitionLength))
406 {
407 /* Round-down to cylinder size */
408 LastUnusedPartitionLength =
409 (DiskEntry->DiskSize - (LastStartingOffset + LastPartitionLength))
410 & ~(DiskEntry->CylinderSize - 1);
411
412 if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
413 {
414 DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
415
416 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
417 0,
418 sizeof(PARTENTRY));
419 if (NewPartEntry == NULL)
420 return;
421
422 RtlZeroMemory (NewPartEntry,
423 sizeof(PARTENTRY));
424
425 NewPartEntry->Unpartitioned = TRUE;
426 NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
427 NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
428
429 /* Append the table to the list */
430 InsertTailList (&DiskEntry->PartListHead,
431 &NewPartEntry->ListEntry);
432 }
433 }
434 }
435 }
436
437 NTSTATUS
438 NTAPI
439 DiskIdentifierQueryRoutine(PWSTR ValueName,
440 ULONG ValueType,
441 PVOID ValueData,
442 ULONG ValueLength,
443 PVOID Context,
444 PVOID EntryContext)
445 {
446 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
447 UNICODE_STRING NameU;
448
449 if (ValueType == REG_SZ &&
450 ValueLength == 20 * sizeof(WCHAR))
451 {
452 NameU.Buffer = (PWCHAR)ValueData;
453 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
454 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
455
456 NameU.Buffer = (PWCHAR)ValueData + 9;
457 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
458
459 return STATUS_SUCCESS;
460 }
461 return STATUS_UNSUCCESSFUL;
462 }
463
464 NTSTATUS
465 NTAPI
466 DiskConfigurationDataQueryRoutine(PWSTR ValueName,
467 ULONG ValueType,
468 PVOID ValueData,
469 ULONG ValueLength,
470 PVOID Context,
471 PVOID EntryContext)
472 {
473 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
474 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
475 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
476 ULONG i;
477
478 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
479 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
480 return STATUS_UNSUCCESSFUL;
481
482 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
483 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
484 /*if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
485 FullResourceDescriptor->PartialResourceList.Revision != 1)
486 return STATUS_UNSUCCESSFUL;*/
487
488 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
489 {
490 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
491 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
492 continue;
493
494 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
495 BiosDiskEntry->DiskGeometry = *DiskGeometry;
496
497 return STATUS_SUCCESS;
498 }
499 return STATUS_UNSUCCESSFUL;
500 }
501
502 NTSTATUS
503 NTAPI
504 SystemConfigurationDataQueryRoutine(PWSTR ValueName,
505 ULONG ValueType,
506 PVOID ValueData,
507 ULONG ValueLength,
508 PVOID Context,
509 PVOID EntryContext)
510 {
511 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
512 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
513 ULONG i;
514
515 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
516 ValueLength < sizeof (CM_FULL_RESOURCE_DESCRIPTOR))
517 return STATUS_UNSUCCESSFUL;
518
519 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
520 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
521 /*if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
522 FullResourceDescriptor->PartialResourceList.Revision != 1)
523 return STATUS_UNSUCCESSFUL;*/
524
525 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
526 {
527 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
528 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
529 continue;
530
531 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*) RtlAllocateHeap(ProcessHeap, 0, FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
532 if (*Int13Drives == NULL)
533 return STATUS_NO_MEMORY;
534 memcpy(*Int13Drives,
535 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
536 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
537 return STATUS_SUCCESS;
538 }
539 return STATUS_UNSUCCESSFUL;
540 }
541 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
542
543 static VOID
544 EnumerateBiosDiskEntries(PPARTLIST PartList)
545 {
546 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
547 WCHAR Name[120];
548 ULONG AdapterCount;
549 ULONG DiskCount;
550 NTSTATUS Status;
551 PCM_INT13_DRIVE_PARAMETER Int13Drives;
552 PBIOSDISKENTRY BiosDiskEntry;
553
554 memset(QueryTable, 0, sizeof(QueryTable));
555
556 QueryTable[1].Name = L"Configuration Data";
557 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
558 Int13Drives = NULL;
559 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
560 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
561 &QueryTable[1],
562 (PVOID)&Int13Drives,
563 NULL);
564 if (!NT_SUCCESS(Status))
565 {
566 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
567 return;
568 }
569
570 AdapterCount = 0;
571 while (1)
572 {
573 swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
574 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
575 Name,
576 &QueryTable[2],
577 NULL,
578 NULL);
579 if (!NT_SUCCESS(Status))
580 {
581 break;
582 }
583
584 swprintf(Name, L"%s\\%lu\\DiskController", 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 while (1)
593 {
594 swprintf(Name, L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount);
595 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
596 Name,
597 &QueryTable[2],
598 NULL,
599 NULL);
600 if (!NT_SUCCESS(Status))
601 {
602 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
603 return;
604 }
605
606 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount);
607 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
608 Name,
609 &QueryTable[2],
610 NULL,
611 NULL);
612 if (NT_SUCCESS(Status))
613 {
614 QueryTable[0].Name = L"Identifier";
615 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
616 QueryTable[1].Name = L"Configuration Data";
617 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
618 DiskCount = 0;
619 while (1)
620 {
621 BiosDiskEntry = (BIOSDISKENTRY*) RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
622 if (BiosDiskEntry == NULL)
623 {
624 break;
625 }
626 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount);
627 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
628 Name,
629 QueryTable,
630 (PVOID)BiosDiskEntry,
631 NULL);
632 if (!NT_SUCCESS(Status))
633 {
634 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
635 break;
636 }
637 BiosDiskEntry->DiskNumber = DiskCount;
638 BiosDiskEntry->Recognized = FALSE;
639
640 if (DiskCount < Int13Drives[0].NumberDrives)
641 {
642 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
643 }
644 else
645 {
646 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
647 }
648
649
650 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
651
652 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
653 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
654 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
655 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
656 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
657 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
658 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
659 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
660 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
661 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
662 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
663
664 DiskCount++;
665 }
666 }
667 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
668 return;
669 }
670 }
671 AdapterCount++;
672 }
673 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
674 }
675
676 static VOID
677 AddDiskToList (HANDLE FileHandle,
678 ULONG DiskNumber,
679 PPARTLIST List)
680 {
681 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
682 DISK_GEOMETRY DiskGeometry;
683 SCSI_ADDRESS ScsiAddress;
684 PDISKENTRY DiskEntry;
685 IO_STATUS_BLOCK Iosb;
686 NTSTATUS Status;
687 PPARTITION_SECTOR Mbr;
688 PULONG Buffer;
689 LARGE_INTEGER FileOffset;
690 WCHAR Identifier[20];
691 ULONG Checksum;
692 ULONG Signature;
693 ULONG i;
694 PLIST_ENTRY ListEntry;
695 PBIOSDISKENTRY BiosDiskEntry;
696
697 Status = NtDeviceIoControlFile (FileHandle,
698 NULL,
699 NULL,
700 NULL,
701 &Iosb,
702 IOCTL_DISK_GET_DRIVE_GEOMETRY,
703 NULL,
704 0,
705 &DiskGeometry,
706 sizeof(DISK_GEOMETRY));
707 if (!NT_SUCCESS (Status))
708 {
709 return;
710 }
711
712 if (DiskGeometry.MediaType != FixedMedia)
713 {
714 return;
715 }
716
717 Status = NtDeviceIoControlFile (FileHandle,
718 NULL,
719 NULL,
720 NULL,
721 &Iosb,
722 IOCTL_SCSI_GET_ADDRESS,
723 NULL,
724 0,
725 &ScsiAddress,
726 sizeof(SCSI_ADDRESS));
727 if (!NT_SUCCESS(Status))
728 {
729 return;
730 }
731
732 Mbr = (PARTITION_SECTOR*) RtlAllocateHeap(ProcessHeap,
733 0,
734 DiskGeometry.BytesPerSector);
735
736 if (Mbr == NULL)
737 {
738 return;
739 }
740
741 FileOffset.QuadPart = 0;
742 Status = NtReadFile(FileHandle,
743 NULL,
744 NULL,
745 NULL,
746 &Iosb,
747 (PVOID)Mbr,
748 DiskGeometry.BytesPerSector,
749 &FileOffset,
750 NULL);
751 if (!NT_SUCCESS(Status))
752 {
753 RtlFreeHeap(ProcessHeap,
754 0,
755 Mbr);
756 DPRINT1("NtReadFile failed, status=%x\n", Status);
757 return;
758 }
759 Signature = Mbr->Signature;
760
761 /* Calculate the MBR checksum */
762 Checksum = 0;
763 Buffer = (PULONG)Mbr;
764 for (i = 0; i < 128; i++)
765 {
766 Checksum += Buffer[i];
767 }
768 Checksum = ~Checksum + 1;
769
770 RtlFreeHeap (ProcessHeap,
771 0,
772 Mbr);
773
774 swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
775 DPRINT("Identifier: %S\n", Identifier);
776
777 DiskEntry = (PDISKENTRY)RtlAllocateHeap (ProcessHeap,
778 0,
779 sizeof(DISKENTRY));
780 if (DiskEntry == NULL)
781 {
782 return;
783 }
784
785 DiskEntry->Checksum = Checksum;
786 DiskEntry->Signature = Signature;
787 if (Signature == 0)
788 {
789 /* If we have no signature, set the disk to dirty. WritePartitionsToDisk creates a new signature */
790 DiskEntry->Modified = TRUE;
791 }
792 DiskEntry->BiosFound = FALSE;
793
794 ListEntry = List->BiosDiskListHead.Flink;
795 while(ListEntry != &List->BiosDiskListHead)
796 {
797 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
798 /* FIXME:
799 * Compare the size from bios and the reported size from driver.
800 * If we have more than one disk with a zero or with the same signatur
801 * we must create new signatures and reboot. After the reboot,
802 * it is possible to identify the disks.
803 */
804 if (BiosDiskEntry->Signature == Signature &&
805 BiosDiskEntry->Checksum == Checksum &&
806 !BiosDiskEntry->Recognized)
807 {
808 if (!DiskEntry->BiosFound)
809 {
810 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
811 DiskEntry->BiosFound = TRUE;
812 BiosDiskEntry->Recognized = TRUE;
813 }
814 else
815 {
816 }
817 }
818 ListEntry = ListEntry->Flink;
819 }
820
821 if (!DiskEntry->BiosFound)
822 {
823 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
824 return;
825 }
826
827 InitializeListHead (&DiskEntry->PartListHead);
828
829 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
830 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
831 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
832 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
833
834 DPRINT ("Cylinders %d\n", DiskEntry->Cylinders);
835 DPRINT ("TracksPerCylinder %d\n", DiskEntry->TracksPerCylinder);
836 DPRINT ("SectorsPerTrack %d\n", DiskEntry->SectorsPerTrack);
837 DPRINT ("BytesPerSector %d\n", DiskEntry->BytesPerSector);
838
839 DiskEntry->DiskSize =
840 DiskGeometry.Cylinders.QuadPart *
841 (ULONGLONG)DiskGeometry.TracksPerCylinder *
842 (ULONGLONG)DiskGeometry.SectorsPerTrack *
843 (ULONGLONG)DiskGeometry.BytesPerSector;
844 DiskEntry->CylinderSize =
845 (ULONGLONG)DiskGeometry.TracksPerCylinder *
846 (ULONGLONG)DiskGeometry.SectorsPerTrack *
847 (ULONGLONG)DiskGeometry.BytesPerSector;
848 DiskEntry->TrackSize =
849 (ULONGLONG)DiskGeometry.SectorsPerTrack *
850 (ULONGLONG)DiskGeometry.BytesPerSector;
851
852 DiskEntry->DiskNumber = DiskNumber;
853 DiskEntry->Port = ScsiAddress.PortNumber;
854 DiskEntry->Bus = ScsiAddress.PathId;
855 DiskEntry->Id = ScsiAddress.TargetId;
856
857 GetDriverName (DiskEntry);
858
859 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, BiosDiskNumber);
860
861 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap (ProcessHeap,
862 0,
863 8192);
864 if (LayoutBuffer == NULL)
865 {
866 return;
867 }
868
869 Status = NtDeviceIoControlFile (FileHandle,
870 NULL,
871 NULL,
872 NULL,
873 &Iosb,
874 IOCTL_DISK_GET_DRIVE_LAYOUT,
875 NULL,
876 0,
877 LayoutBuffer,
878 8192);
879 if (NT_SUCCESS (Status))
880 {
881 if (LayoutBuffer->PartitionCount == 0)
882 {
883 DiskEntry->NewDisk = TRUE;
884 }
885
886 AddPartitionToList (DiskNumber,
887 DiskEntry,
888 LayoutBuffer);
889
890 ScanForUnpartitionedDiskSpace (DiskEntry);
891 }
892
893 RtlFreeHeap (ProcessHeap,
894 0,
895 LayoutBuffer);
896 }
897
898
899 PPARTLIST
900 CreatePartitionList (SHORT Left,
901 SHORT Top,
902 SHORT Right,
903 SHORT Bottom)
904 {
905 PPARTLIST List;
906 OBJECT_ATTRIBUTES ObjectAttributes;
907 SYSTEM_DEVICE_INFORMATION Sdi;
908 IO_STATUS_BLOCK Iosb;
909 SIZE_T ReturnSize;
910 NTSTATUS Status;
911 ULONG DiskNumber;
912 WCHAR Buffer[MAX_PATH];
913 UNICODE_STRING Name;
914 HANDLE FileHandle;
915
916 List = (PPARTLIST)RtlAllocateHeap (ProcessHeap,
917 0,
918 sizeof (PARTLIST));
919 if (List == NULL)
920 return NULL;
921
922 List->Left = Left;
923 List->Top = Top;
924 List->Right = Right;
925 List->Bottom = Bottom;
926
927 List->Line = 0;
928
929 List->TopDisk = (ULONG)-1;
930 List->TopPartition = (ULONG)-1;
931
932 List->CurrentDisk = NULL;
933 List->CurrentPartition = NULL;
934
935 InitializeListHead (&List->DiskListHead);
936 InitializeListHead (&List->BiosDiskListHead);
937
938 EnumerateBiosDiskEntries(List);
939
940 Status = NtQuerySystemInformation (SystemDeviceInformation,
941 &Sdi,
942 sizeof(SYSTEM_DEVICE_INFORMATION),
943 &ReturnSize);
944 if (!NT_SUCCESS (Status))
945 {
946 RtlFreeHeap (ProcessHeap, 0, List);
947 return NULL;
948 }
949
950 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
951 {
952 swprintf (Buffer,
953 L"\\Device\\Harddisk%d\\Partition0",
954 DiskNumber);
955 RtlInitUnicodeString (&Name,
956 Buffer);
957
958 InitializeObjectAttributes (&ObjectAttributes,
959 &Name,
960 0,
961 NULL,
962 NULL);
963
964 Status = NtOpenFile (&FileHandle,
965 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
966 &ObjectAttributes,
967 &Iosb,
968 FILE_SHARE_READ,
969 FILE_SYNCHRONOUS_IO_NONALERT);
970 if (NT_SUCCESS(Status))
971 {
972 AddDiskToList (FileHandle,
973 DiskNumber,
974 List);
975
976 NtClose(FileHandle);
977 }
978 }
979
980 AssignDriverLetters (List);
981
982 List->TopDisk = 0;
983 List->TopPartition = 0;
984
985 /* Search for first usable disk and partition */
986 if (IsListEmpty (&List->DiskListHead))
987 {
988 List->CurrentDisk = NULL;
989 List->CurrentPartition = NULL;
990 }
991 else
992 {
993 List->CurrentDisk =
994 CONTAINING_RECORD (List->DiskListHead.Flink,
995 DISKENTRY,
996 ListEntry);
997
998 if (IsListEmpty (&List->CurrentDisk->PartListHead))
999 {
1000 List->CurrentPartition = 0;
1001 }
1002 else
1003 {
1004 List->CurrentPartition =
1005 CONTAINING_RECORD (List->CurrentDisk->PartListHead.Flink,
1006 PARTENTRY,
1007 ListEntry);
1008 }
1009 }
1010
1011 return List;
1012 }
1013
1014
1015 VOID
1016 DestroyPartitionList (PPARTLIST List)
1017 {
1018 PDISKENTRY DiskEntry;
1019 PBIOSDISKENTRY BiosDiskEntry;
1020 PPARTENTRY PartEntry;
1021 PLIST_ENTRY Entry;
1022
1023 /* Release disk and partition info */
1024 while (!IsListEmpty (&List->DiskListHead))
1025 {
1026 Entry = RemoveHeadList (&List->DiskListHead);
1027 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1028
1029 /* Release driver name */
1030 RtlFreeUnicodeString(&DiskEntry->DriverName);
1031
1032 /* Release partition array */
1033 while (!IsListEmpty (&DiskEntry->PartListHead))
1034 {
1035 Entry = RemoveHeadList (&DiskEntry->PartListHead);
1036 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
1037
1038 RtlFreeHeap (ProcessHeap,
1039 0,
1040 PartEntry);
1041 }
1042
1043 /* Release disk entry */
1044 RtlFreeHeap (ProcessHeap, 0, DiskEntry);
1045 }
1046
1047 /* release the bios disk info */
1048 while(!IsListEmpty(&List->BiosDiskListHead))
1049 {
1050 Entry = RemoveHeadList(&List->BiosDiskListHead);
1051 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1052
1053 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1054 }
1055
1056 /* Release list head */
1057 RtlFreeHeap (ProcessHeap, 0, List);
1058 }
1059
1060
1061 static VOID
1062 PrintEmptyLine (PPARTLIST List)
1063 {
1064 COORD coPos;
1065 DWORD Written;
1066 USHORT Width;
1067 USHORT Height;
1068
1069 Width = List->Right - List->Left - 1;
1070 Height = List->Bottom - List->Top - 2;
1071
1072
1073 coPos.X = List->Left + 1;
1074 coPos.Y = List->Top + 1 + List->Line;
1075
1076 if (List->Line >= 0 && List->Line <= Height)
1077 {
1078 FillConsoleOutputAttribute (StdOutput,
1079 FOREGROUND_WHITE | BACKGROUND_BLUE,
1080 Width,
1081 coPos,
1082 &Written);
1083
1084 FillConsoleOutputCharacterA (StdOutput,
1085 ' ',
1086 Width,
1087 coPos,
1088 &Written);
1089 }
1090 List->Line++;
1091 }
1092
1093
1094 static VOID
1095 PrintPartitionData (PPARTLIST List,
1096 PDISKENTRY DiskEntry,
1097 PPARTENTRY PartEntry)
1098 {
1099 CHAR LineBuffer[128];
1100 COORD coPos;
1101 DWORD Written;
1102 USHORT Width;
1103 USHORT Height;
1104
1105 LARGE_INTEGER PartSize;
1106 PCHAR Unit;
1107 UCHAR Attribute;
1108 PCHAR PartType;
1109
1110 Width = List->Right - List->Left - 1;
1111 Height = List->Bottom - List->Top - 2;
1112
1113
1114 coPos.X = List->Left + 1;
1115 coPos.Y = List->Top + 1 + List->Line;
1116
1117 if (PartEntry->Unpartitioned == TRUE)
1118 {
1119 #if 0
1120 if (PartEntry->UnpartitionledLength >= 0x280000000ULL) /* 10 GB */
1121 {
1122 PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 29)) >> 30;
1123 Unit = MUIGetString(STRING_GB);
1124 }
1125 else
1126 #endif
1127 if (PartEntry->UnpartitionedLength >= 0xA00000ULL) /* 10 MB */
1128 {
1129 PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;
1130 Unit = MUIGetString(STRING_MB);
1131 }
1132 else
1133 {
1134 PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 9)) >> 10;
1135 Unit = MUIGetString(STRING_KB);
1136 }
1137
1138 sprintf (LineBuffer,
1139 MUIGetString(STRING_UNPSPACE),
1140 PartSize.u.LowPart,
1141 Unit);
1142 }
1143 else
1144 {
1145 /* Determine partition type */
1146 PartType = NULL;
1147 if (PartEntry->New == TRUE)
1148 {
1149 PartType = MUIGetString(STRING_UNFORMATTED);
1150 }
1151 else if (PartEntry->Unpartitioned == FALSE)
1152 {
1153 if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
1154 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
1155 (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
1156 (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
1157 {
1158 PartType = "FAT";
1159 }
1160 else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
1161 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
1162 {
1163 PartType = "FAT32";
1164 }
1165 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_EXT2)
1166 {
1167 PartType = "EXT2";
1168 }
1169 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
1170 {
1171 PartType = "NTFS"; /* FIXME: Not quite correct! */
1172 }
1173 }
1174
1175 #if 0
1176 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
1177 {
1178 PartSize.QuadPart = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
1179 Unit = MUIGetString(STRING_GB);
1180 }
1181 else
1182 #endif
1183 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0xA00000LL) /* 10 MB */
1184 {
1185 PartSize.QuadPart = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
1186 Unit = MUIGetString(STRING_MB);
1187 }
1188 else
1189 {
1190 PartSize.QuadPart = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 9)) >> 10;
1191 Unit = MUIGetString(STRING_KB);
1192 }
1193
1194 if (PartType == NULL)
1195 {
1196 sprintf (LineBuffer,
1197 MUIGetString(STRING_HDDINFOUNK5),
1198 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1199 (PartEntry->DriveLetter == 0) ? '-' : ':',
1200 PartEntry->PartInfo[0].PartitionType,
1201 PartSize.u.LowPart,
1202 Unit);
1203 }
1204 else
1205 {
1206 sprintf (LineBuffer,
1207 "%c%c %-24s %6lu %s",
1208 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1209 (PartEntry->DriveLetter == 0) ? '-' : ':',
1210 PartType,
1211 PartSize.u.LowPart,
1212 Unit);
1213 }
1214 }
1215
1216 Attribute = (List->CurrentDisk == DiskEntry &&
1217 List->CurrentPartition == PartEntry) ?
1218 FOREGROUND_BLUE | BACKGROUND_WHITE :
1219 FOREGROUND_WHITE | BACKGROUND_BLUE;
1220
1221 if (List->Line >= 0 && List->Line <= Height)
1222 {
1223 FillConsoleOutputCharacterA (StdOutput,
1224 ' ',
1225 Width,
1226 coPos,
1227 &Written);
1228 }
1229 coPos.X += 4;
1230 Width -= 8;
1231 if (List->Line >= 0 && List->Line <= Height)
1232 {
1233 FillConsoleOutputAttribute (StdOutput,
1234 Attribute,
1235 Width,
1236 coPos,
1237 &Written);
1238 }
1239 coPos.X++;
1240 Width -= 2;
1241 if (List->Line >= 0 && List->Line <= Height)
1242 {
1243 WriteConsoleOutputCharacterA (StdOutput,
1244 LineBuffer,
1245 min (strlen (LineBuffer), Width),
1246 coPos,
1247 &Written);
1248 }
1249 List->Line++;
1250 }
1251
1252
1253 static VOID
1254 PrintDiskData (PPARTLIST List,
1255 PDISKENTRY DiskEntry)
1256 {
1257 PPARTENTRY PartEntry;
1258 CHAR LineBuffer[128];
1259 COORD coPos;
1260 DWORD Written;
1261 USHORT Width;
1262 USHORT Height;
1263 ULARGE_INTEGER DiskSize;
1264 PCHAR Unit;
1265
1266 Width = List->Right - List->Left - 1;
1267 Height = List->Bottom - List->Top - 2;
1268
1269
1270 coPos.X = List->Left + 1;
1271 coPos.Y = List->Top + 1 + List->Line;
1272
1273 #if 0
1274 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
1275 {
1276 DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 29)) >> 30;
1277 Unit = MUIGetString(STRING_GB);
1278 }
1279 else
1280 #endif
1281 {
1282 DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 19)) >> 20;
1283 if (DiskSize.QuadPart == 0)
1284 DiskSize.QuadPart = 1;
1285 Unit = MUIGetString(STRING_MB);
1286 }
1287
1288 if (DiskEntry->DriverName.Length > 0)
1289 {
1290 sprintf (LineBuffer,
1291 MUIGetString(STRING_HDINFOPARTSELECT),
1292 DiskSize.u.LowPart,
1293 Unit,
1294 DiskEntry->DiskNumber,
1295 DiskEntry->Port,
1296 DiskEntry->Bus,
1297 DiskEntry->Id,
1298 DiskEntry->DriverName.Buffer);
1299 }
1300 else
1301 {
1302 sprintf (LineBuffer,
1303 MUIGetString(STRING_HDDINFOUNK6),
1304 DiskSize.u.LowPart,
1305 Unit,
1306 DiskEntry->DiskNumber,
1307 DiskEntry->Port,
1308 DiskEntry->Bus,
1309 DiskEntry->Id);
1310 }
1311 if (List->Line >= 0 && List->Line <= Height)
1312 {
1313 FillConsoleOutputAttribute (StdOutput,
1314 FOREGROUND_WHITE | BACKGROUND_BLUE,
1315 Width,
1316 coPos,
1317 &Written);
1318
1319 FillConsoleOutputCharacterA (StdOutput,
1320 ' ',
1321 Width,
1322 coPos,
1323 &Written);
1324 }
1325
1326 coPos.X++;
1327 if (List->Line >= 0 && List->Line <= Height)
1328 {
1329 WriteConsoleOutputCharacterA (StdOutput,
1330 LineBuffer,
1331 min ((USHORT)strlen (LineBuffer), Width - 2),
1332 coPos,
1333 &Written);
1334 }
1335 List->Line++;
1336
1337 /* Print separator line */
1338 PrintEmptyLine (List);
1339
1340 /* Print partition lines*/
1341 LIST_FOR_EACH(PartEntry, &DiskEntry->PartListHead, PARTENTRY, ListEntry)
1342 {
1343 /* Print disk entry */
1344 PrintPartitionData (List,
1345 DiskEntry,
1346 PartEntry);
1347 }
1348
1349 /* Print separator line */
1350 PrintEmptyLine (List);
1351 }
1352
1353
1354 VOID
1355 DrawPartitionList (PPARTLIST List)
1356 {
1357 PLIST_ENTRY Entry, Entry2;
1358 PDISKENTRY DiskEntry;
1359 PPARTENTRY PartEntry = NULL;
1360 COORD coPos;
1361 DWORD Written;
1362 SHORT i;
1363 SHORT CurrentDiskLine;
1364 SHORT CurrentPartLine;
1365 SHORT LastLine;
1366 BOOL CurrentPartLineFound = FALSE;
1367 BOOL CurrentDiskLineFound = FALSE;
1368
1369 /* Calculate the line of the current disk and partition */
1370 CurrentDiskLine = 0;
1371 CurrentPartLine = 0;
1372 LastLine = 0;
1373 Entry = List->DiskListHead.Flink;
1374 while (Entry != &List->DiskListHead)
1375 {
1376 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1377 LastLine += 2;
1378 if (CurrentPartLineFound == FALSE)
1379 {
1380 CurrentPartLine += 2;
1381 }
1382 Entry2 = DiskEntry->PartListHead.Flink;
1383 while (Entry2 != &DiskEntry->PartListHead)
1384 {
1385 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1386 if (PartEntry == List->CurrentPartition)
1387 {
1388 CurrentPartLineFound = TRUE;
1389 }
1390 Entry2 = Entry2->Flink;
1391 if (CurrentPartLineFound == FALSE)
1392 {
1393 CurrentPartLine++;
1394 }
1395 LastLine++;
1396 }
1397 if (DiskEntry == List->CurrentDisk)
1398 {
1399 CurrentDiskLineFound = TRUE;
1400 }
1401 Entry = Entry->Flink;
1402 if (Entry != &List->DiskListHead)
1403 {
1404 if (CurrentDiskLineFound == FALSE)
1405 {
1406 CurrentPartLine ++;
1407 CurrentDiskLine = CurrentPartLine;
1408 }
1409 LastLine++;
1410 }
1411 else
1412 {
1413 LastLine--;
1414 }
1415 }
1416
1417 /* If it possible, make the disk name visible */
1418 if (CurrentPartLine < List->Offset)
1419 {
1420 List->Offset = CurrentPartLine;
1421 }
1422 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1423 {
1424 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1425 }
1426 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1427 {
1428 List->Offset = CurrentDiskLine;
1429 }
1430
1431
1432 /* draw upper left corner */
1433 coPos.X = List->Left;
1434 coPos.Y = List->Top;
1435 FillConsoleOutputCharacterA (StdOutput,
1436 0xDA, // '+',
1437 1,
1438 coPos,
1439 &Written);
1440
1441 /* draw upper edge */
1442 coPos.X = List->Left + 1;
1443 coPos.Y = List->Top;
1444 if (List->Offset == 0)
1445 {
1446 FillConsoleOutputCharacterA (StdOutput,
1447 0xC4, // '-',
1448 List->Right - List->Left - 1,
1449 coPos,
1450 &Written);
1451 }
1452 else
1453 {
1454 FillConsoleOutputCharacterA (StdOutput,
1455 0xC4, // '-',
1456 List->Right - List->Left - 5,
1457 coPos,
1458 &Written);
1459 coPos.X = List->Right - 5;
1460 WriteConsoleOutputCharacterA (StdOutput,
1461 "(\x18)", // "(up)"
1462 3,
1463 coPos,
1464 &Written);
1465 coPos.X = List->Right - 2;
1466 FillConsoleOutputCharacterA (StdOutput,
1467 0xC4, // '-',
1468 2,
1469 coPos,
1470 &Written);
1471 }
1472
1473 /* draw upper right corner */
1474 coPos.X = List->Right;
1475 coPos.Y = List->Top;
1476 FillConsoleOutputCharacterA (StdOutput,
1477 0xBF, // '+',
1478 1,
1479 coPos,
1480 &Written);
1481
1482 /* draw left and right edge */
1483 for (i = List->Top + 1; i < List->Bottom; i++)
1484 {
1485 coPos.X = List->Left;
1486 coPos.Y = i;
1487 FillConsoleOutputCharacterA (StdOutput,
1488 0xB3, // '|',
1489 1,
1490 coPos,
1491 &Written);
1492
1493 coPos.X = List->Right;
1494 FillConsoleOutputCharacterA (StdOutput,
1495 0xB3, //'|',
1496 1,
1497 coPos,
1498 &Written);
1499 }
1500
1501 /* draw lower left corner */
1502 coPos.X = List->Left;
1503 coPos.Y = List->Bottom;
1504 FillConsoleOutputCharacterA (StdOutput,
1505 0xC0, // '+',
1506 1,
1507 coPos,
1508 &Written);
1509
1510 /* draw lower edge */
1511 coPos.X = List->Left + 1;
1512 coPos.Y = List->Bottom;
1513 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1514 {
1515 FillConsoleOutputCharacterA (StdOutput,
1516 0xC4, // '-',
1517 List->Right - List->Left - 1,
1518 coPos,
1519 &Written);
1520 }
1521 else
1522 {
1523 FillConsoleOutputCharacterA (StdOutput,
1524 0xC4, // '-',
1525 List->Right - List->Left - 5,
1526 coPos,
1527 &Written);
1528 coPos.X = List->Right - 5;
1529 WriteConsoleOutputCharacterA (StdOutput,
1530 "(\x19)", // "(down)"
1531 3,
1532 coPos,
1533 &Written);
1534 coPos.X = List->Right - 2;
1535 FillConsoleOutputCharacterA (StdOutput,
1536 0xC4, // '-',
1537 2,
1538 coPos,
1539 &Written);
1540 }
1541
1542 /* draw lower right corner */
1543 coPos.X = List->Right;
1544 coPos.Y = List->Bottom;
1545 FillConsoleOutputCharacterA (StdOutput,
1546 0xD9, // '+',
1547 1,
1548 coPos,
1549 &Written);
1550
1551 /* print list entries */
1552 List->Line = - List->Offset;
1553
1554 LIST_FOR_EACH(DiskEntry, &List->DiskListHead, DISKENTRY, ListEntry)
1555 {
1556 /* Print disk entry */
1557 PrintDiskData (List,
1558 DiskEntry);
1559 }
1560 }
1561
1562
1563 DWORD
1564 SelectPartition(PPARTLIST List, ULONG DiskNumber, ULONG PartitionNumber)
1565 {
1566 PDISKENTRY DiskEntry;
1567 PPARTENTRY PartEntry;
1568 PLIST_ENTRY Entry1;
1569 PLIST_ENTRY Entry2;
1570 ULONG i;
1571
1572 /* Check for empty disks */
1573 if (IsListEmpty (&List->DiskListHead))
1574 return FALSE;
1575
1576 /* Check for first usable entry on next disk */
1577 Entry1 = List->CurrentDisk->ListEntry.Flink;
1578 while (Entry1 != &List->DiskListHead)
1579 {
1580 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1581
1582 if (DiskEntry->DiskNumber == DiskNumber)
1583 {
1584 Entry2 = DiskEntry->PartListHead.Flink;
1585 while (Entry2 != &DiskEntry->PartListHead)
1586 {
1587 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1588
1589 for (i = 0; i < 4; i++)
1590 {
1591 if (PartEntry->PartInfo[i].PartitionNumber == PartitionNumber)
1592 {
1593 List->CurrentDisk = DiskEntry;
1594 List->CurrentPartition = PartEntry;
1595 DrawPartitionList (List);
1596 return TRUE;
1597 }
1598 }
1599 Entry2 = Entry2->Flink;
1600 }
1601 return FALSE;
1602 }
1603 Entry1 = Entry1->Flink;
1604 }
1605 return FALSE;
1606 }
1607
1608
1609 VOID
1610 ScrollDownPartitionList (PPARTLIST List)
1611 {
1612 PDISKENTRY DiskEntry;
1613 PPARTENTRY PartEntry;
1614 PLIST_ENTRY Entry1;
1615 PLIST_ENTRY Entry2;
1616
1617 /* Check for empty disks */
1618 if (IsListEmpty (&List->DiskListHead))
1619 return;
1620
1621 /* Check for next usable entry on current disk */
1622 if (List->CurrentPartition != NULL)
1623 {
1624 Entry2 = List->CurrentPartition->ListEntry.Flink;
1625 while (Entry2 != &List->CurrentDisk->PartListHead)
1626 {
1627 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1628
1629 // if (PartEntry->HidePartEntry == FALSE)
1630 {
1631 List->CurrentPartition = PartEntry;
1632 DrawPartitionList (List);
1633 return;
1634 }
1635 Entry2 = Entry2->Flink;
1636 }
1637 }
1638
1639 /* Check for first usable entry on next disk */
1640 if (List->CurrentDisk != NULL)
1641 {
1642 Entry1 = List->CurrentDisk->ListEntry.Flink;
1643 while (Entry1 != &List->DiskListHead)
1644 {
1645 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1646
1647 Entry2 = DiskEntry->PartListHead.Flink;
1648 while (Entry2 != &DiskEntry->PartListHead)
1649 {
1650 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1651
1652 // if (PartEntry->HidePartEntry == FALSE)
1653 {
1654 List->CurrentDisk = DiskEntry;
1655 List->CurrentPartition = PartEntry;
1656 DrawPartitionList (List);
1657 return;
1658 }
1659
1660 Entry2 = Entry2->Flink;
1661 }
1662
1663 Entry1 = Entry1->Flink;
1664 }
1665 }
1666 }
1667
1668
1669 VOID
1670 ScrollUpPartitionList (PPARTLIST List)
1671 {
1672 PDISKENTRY DiskEntry;
1673 PPARTENTRY PartEntry;
1674 PLIST_ENTRY Entry1;
1675 PLIST_ENTRY Entry2;
1676
1677 /* Check for empty disks */
1678 if (IsListEmpty (&List->DiskListHead))
1679 return;
1680
1681 /* check for previous usable entry on current disk */
1682 if (List->CurrentPartition != NULL)
1683 {
1684 Entry2 = List->CurrentPartition->ListEntry.Blink;
1685 while (Entry2 != &List->CurrentDisk->PartListHead)
1686 {
1687 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1688
1689 // if (PartEntry->HidePartEntry == FALSE)
1690 {
1691 List->CurrentPartition = PartEntry;
1692 DrawPartitionList (List);
1693 return;
1694 }
1695 Entry2 = Entry2->Blink;
1696 }
1697 }
1698
1699
1700 /* check for last usable entry on previous disk */
1701 if (List->CurrentDisk != NULL)
1702 {
1703 Entry1 = List->CurrentDisk->ListEntry.Blink;
1704 while (Entry1 != &List->DiskListHead)
1705 {
1706 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1707
1708 Entry2 = DiskEntry->PartListHead.Blink;
1709 while (Entry2 != &DiskEntry->PartListHead)
1710 {
1711 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1712
1713 // if (PartEntry->HidePartEntry == FALSE)
1714 {
1715 List->CurrentDisk = DiskEntry;
1716 List->CurrentPartition = PartEntry;
1717 DrawPartitionList (List);
1718 return;
1719 }
1720
1721 Entry2 = Entry2->Blink;
1722 }
1723
1724 Entry1 = Entry1->Blink;
1725 }
1726 }
1727 }
1728
1729
1730 static PPARTENTRY
1731 GetPrevPartitionedEntry (PDISKENTRY DiskEntry,
1732 PPARTENTRY CurrentEntry)
1733 {
1734 PPARTENTRY PrevEntry;
1735 PLIST_ENTRY Entry;
1736
1737 if (CurrentEntry->ListEntry.Blink == &DiskEntry->PartListHead)
1738 return NULL;
1739
1740 Entry = CurrentEntry->ListEntry.Blink;
1741 while (Entry != &DiskEntry->PartListHead)
1742 {
1743 PrevEntry = CONTAINING_RECORD (Entry,
1744 PARTENTRY,
1745 ListEntry);
1746 if (PrevEntry->Unpartitioned == FALSE)
1747 return PrevEntry;
1748
1749 Entry = Entry->Blink;
1750 }
1751
1752 return NULL;
1753 }
1754
1755
1756 static PPARTENTRY
1757 GetNextPartitionedEntry (PDISKENTRY DiskEntry,
1758 PPARTENTRY CurrentEntry)
1759 {
1760 PPARTENTRY NextEntry;
1761 PLIST_ENTRY Entry;
1762
1763 if (CurrentEntry->ListEntry.Flink == &DiskEntry->PartListHead)
1764 return NULL;
1765
1766 Entry = CurrentEntry->ListEntry.Flink;
1767 while (Entry != &DiskEntry->PartListHead)
1768 {
1769 NextEntry = CONTAINING_RECORD (Entry,
1770 PARTENTRY,
1771 ListEntry);
1772 if (NextEntry->Unpartitioned == FALSE)
1773 return NextEntry;
1774
1775 Entry = Entry->Flink;
1776 }
1777
1778 return NULL;
1779 }
1780
1781
1782 static PPARTENTRY
1783 GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry,
1784 PPARTENTRY PartEntry)
1785 {
1786 PPARTENTRY PrevPartEntry;
1787
1788 if (PartEntry->ListEntry.Blink != &DiskEntry->PartListHead)
1789 {
1790 PrevPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Blink,
1791 PARTENTRY,
1792 ListEntry);
1793 if (PrevPartEntry->Unpartitioned == TRUE)
1794 return PrevPartEntry;
1795 }
1796
1797 return NULL;
1798 }
1799
1800
1801 static PPARTENTRY
1802 GetNextUnpartitionedEntry (PDISKENTRY DiskEntry,
1803 PPARTENTRY PartEntry)
1804 {
1805 PPARTENTRY NextPartEntry;
1806
1807 if (PartEntry->ListEntry.Flink != &DiskEntry->PartListHead)
1808 {
1809 NextPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Flink,
1810 PARTENTRY,
1811 ListEntry);
1812 if (NextPartEntry->Unpartitioned == TRUE)
1813 return NextPartEntry;
1814 }
1815
1816 return NULL;
1817 }
1818
1819
1820 VOID
1821 CreateNewPartition (PPARTLIST List,
1822 ULONGLONG PartitionSize,
1823 BOOLEAN AutoCreate)
1824 {
1825 PDISKENTRY DiskEntry;
1826 PPARTENTRY PartEntry;
1827 PPARTENTRY PrevPartEntry;
1828 PPARTENTRY NextPartEntry;
1829 PPARTENTRY NewPartEntry;
1830
1831 if (List == NULL ||
1832 List->CurrentDisk == NULL ||
1833 List->CurrentPartition == NULL ||
1834 List->CurrentPartition->Unpartitioned == FALSE)
1835 {
1836 return;
1837 }
1838
1839 DiskEntry = List->CurrentDisk;
1840 PartEntry = List->CurrentPartition;
1841
1842 if (AutoCreate == TRUE ||
1843 PartitionSize == PartEntry->UnpartitionedLength)
1844 {
1845 /* Convert current entry to 'new (unformatted)' */
1846 PartEntry->FormatState = Unformatted;
1847 PartEntry->PartInfo[0].StartingOffset.QuadPart =
1848 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1849 PartEntry->PartInfo[0].PartitionLength.QuadPart =
1850 PartEntry->UnpartitionedLength - DiskEntry->TrackSize;
1851 PartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1852 PartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1853 PartEntry->PartInfo[0].RewritePartition = TRUE;
1854 PartEntry->PartInfo[1].RewritePartition = TRUE;
1855 PartEntry->PartInfo[2].RewritePartition = TRUE;
1856 PartEntry->PartInfo[3].RewritePartition = TRUE;
1857
1858 /* Get previous and next partition entries */
1859 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1860 PartEntry);
1861 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1862 PartEntry);
1863
1864 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1865 {
1866 /* Current entry is in the middle of the list */
1867
1868 /* Copy previous container partition data to current entry */
1869 RtlCopyMemory (&PartEntry->PartInfo[1],
1870 &PrevPartEntry->PartInfo[1],
1871 sizeof(PARTITION_INFORMATION));
1872 PartEntry->PartInfo[1].RewritePartition = TRUE;
1873
1874 /* Update previous container partition data */
1875
1876 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1877 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1878
1879 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1880 {
1881 /* Special case - previous partition is first partition */
1882 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1883 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1884 }
1885 else
1886 {
1887 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1888 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1889 }
1890
1891 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1892 }
1893 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
1894 {
1895 /* Current entry is the first entry */
1896 return;
1897 }
1898 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
1899 {
1900 /* Current entry is the last entry */
1901
1902 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1903 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1904
1905 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1906 {
1907 /* Special case - previous partition is first partition */
1908 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1909 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1910 }
1911 else
1912 {
1913 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1914 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1915 }
1916
1917 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
1918 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
1919 (1024LL * 255LL * 63LL * 512LL))
1920 {
1921 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
1922 }
1923 else
1924 {
1925 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
1926 }
1927
1928 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
1929 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
1930 }
1931
1932 PartEntry->AutoCreate = AutoCreate;
1933 PartEntry->New = TRUE;
1934 PartEntry->Unpartitioned = FALSE;
1935 PartEntry->UnpartitionedOffset = 0ULL;
1936 PartEntry->UnpartitionedLength = 0ULL;
1937 }
1938 else
1939 {
1940 /* Insert an initialize a new partition entry */
1941 NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
1942 0,
1943 sizeof(PARTENTRY));
1944 if (NewPartEntry == NULL)
1945 return;
1946
1947 RtlZeroMemory (NewPartEntry,
1948 sizeof(PARTENTRY));
1949
1950 /* Insert the new entry into the list */
1951 InsertTailList (&PartEntry->ListEntry,
1952 &NewPartEntry->ListEntry);
1953
1954 NewPartEntry->New = TRUE;
1955
1956 NewPartEntry->FormatState = Unformatted;
1957 NewPartEntry->PartInfo[0].StartingOffset.QuadPart =
1958 PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
1959 NewPartEntry->PartInfo[0].PartitionLength.QuadPart =
1960 PartitionSize - DiskEntry->TrackSize;
1961 NewPartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
1962 NewPartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
1963 NewPartEntry->PartInfo[0].RewritePartition = TRUE;
1964 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1965 NewPartEntry->PartInfo[2].RewritePartition = TRUE;
1966 NewPartEntry->PartInfo[3].RewritePartition = TRUE;
1967
1968 /* Get previous and next partition entries */
1969 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
1970 NewPartEntry);
1971 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
1972 NewPartEntry);
1973
1974 if (PrevPartEntry != NULL && NextPartEntry != NULL)
1975 {
1976 /* Current entry is in the middle of the list */
1977
1978 /* Copy previous container partition data to current entry */
1979 RtlCopyMemory (&NewPartEntry->PartInfo[1],
1980 &PrevPartEntry->PartInfo[1],
1981 sizeof(PARTITION_INFORMATION));
1982 NewPartEntry->PartInfo[1].RewritePartition = TRUE;
1983
1984 /* Update previous container partition data */
1985
1986 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
1987 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
1988
1989 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
1990 {
1991 /* Special case - previous partition is first partition */
1992 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1993 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
1994 }
1995 else
1996 {
1997 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
1998 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
1999 }
2000
2001 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
2002 }
2003 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2004 {
2005 /* Current entry is the first entry */
2006 return;
2007 }
2008 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2009 {
2010 /* Current entry is the last entry */
2011
2012 PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
2013 NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
2014
2015 if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
2016 {
2017 /* Special case - previous partition is first partition */
2018 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
2019 DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
2020 }
2021 else
2022 {
2023 PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
2024 NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
2025 }
2026
2027 if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
2028 PartEntry->PartInfo[1].PartitionLength.QuadPart) <
2029 (1024LL * 255LL * 63LL * 512LL))
2030 {
2031 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
2032 }
2033 else
2034 {
2035 PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
2036 }
2037
2038 PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
2039 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
2040 }
2041
2042 /* Update offset and size of the remaining unpartitioned disk space */
2043 PartEntry->UnpartitionedOffset += PartitionSize;
2044 PartEntry->UnpartitionedLength -= PartitionSize;
2045 }
2046
2047 DiskEntry->Modified = TRUE;
2048
2049 UpdatePartitionNumbers (DiskEntry);
2050
2051 AssignDriverLetters (List);
2052 }
2053
2054
2055 VOID
2056 DeleteCurrentPartition (PPARTLIST List)
2057 {
2058 PDISKENTRY DiskEntry;
2059 PPARTENTRY PartEntry;
2060 PPARTENTRY PrevPartEntry;
2061 PPARTENTRY NextPartEntry;
2062
2063 if (List == NULL ||
2064 List->CurrentDisk == NULL ||
2065 List->CurrentPartition == NULL ||
2066 List->CurrentPartition->Unpartitioned == TRUE)
2067 {
2068 return;
2069 }
2070
2071 DiskEntry = List->CurrentDisk;
2072 PartEntry = List->CurrentPartition;
2073
2074 /* Adjust container partition entries */
2075
2076 /* Get previous and next partition entries */
2077 PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
2078 PartEntry);
2079 NextPartEntry = GetNextPartitionedEntry (DiskEntry,
2080 PartEntry);
2081
2082 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2083 {
2084 /* Current entry is in the middle of the list */
2085
2086 /*
2087 * The first extended partition can not be deleted
2088 * as long as other extended partitions are present.
2089 */
2090 if (PrevPartEntry->ListEntry.Blink == &DiskEntry->PartListHead)
2091 return;
2092
2093 /* Copy previous container partition data to current entry */
2094 RtlCopyMemory (&PrevPartEntry->PartInfo[1],
2095 &PartEntry->PartInfo[1],
2096 sizeof(PARTITION_INFORMATION));
2097 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
2098 }
2099 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2100 {
2101 /*
2102 * A primary partition can not be deleted as long as
2103 * extended partitions are present.
2104 */
2105 return;
2106 }
2107 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2108 {
2109 /* Current entry is the last entry */
2110 RtlZeroMemory (&PrevPartEntry->PartInfo[1],
2111 sizeof(PARTITION_INFORMATION));
2112 PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
2113 }
2114
2115
2116 /* Adjust unpartitioned disk space entries */
2117
2118 /* Get pointer to previous and next unpartitioned entries */
2119 PrevPartEntry = GetPrevUnpartitionedEntry (DiskEntry,
2120 PartEntry);
2121
2122 NextPartEntry = GetNextUnpartitionedEntry (DiskEntry,
2123 PartEntry);
2124
2125 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2126 {
2127 /* Merge previous, current and next unpartitioned entry */
2128
2129 /* Adjust the previous entries length */
2130 PrevPartEntry->UnpartitionedLength +=
2131 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize +
2132 NextPartEntry->UnpartitionedLength);
2133
2134 /* Remove the current entry */
2135 RemoveEntryList (&PartEntry->ListEntry);
2136 RtlFreeHeap (ProcessHeap,
2137 0,
2138 PartEntry);
2139
2140 /* Remove the next entry */
2141 RemoveEntryList (&NextPartEntry->ListEntry);
2142 RtlFreeHeap (ProcessHeap,
2143 0,
2144 NextPartEntry);
2145
2146 /* Update current partition */
2147 List->CurrentPartition = PrevPartEntry;
2148 }
2149 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2150 {
2151 /* Merge current and previous unpartitioned entry */
2152
2153 /* Adjust the previous entries length */
2154 PrevPartEntry->UnpartitionedLength +=
2155 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
2156
2157 /* Remove the current entry */
2158 RemoveEntryList (&PartEntry->ListEntry);
2159 RtlFreeHeap (ProcessHeap,
2160 0,
2161 PartEntry);
2162
2163 /* Update current partition */
2164 List->CurrentPartition = PrevPartEntry;
2165 }
2166 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2167 {
2168 /* Merge current and next unpartitioned entry */
2169
2170 /* Adjust the next entries offset and length */
2171 NextPartEntry->UnpartitionedOffset =
2172 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
2173 NextPartEntry->UnpartitionedLength +=
2174 (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
2175
2176 /* Remove the current entry */
2177 RemoveEntryList (&PartEntry->ListEntry);
2178 RtlFreeHeap (ProcessHeap,
2179 0,
2180 PartEntry);
2181
2182 /* Update current partition */
2183 List->CurrentPartition = NextPartEntry;
2184 }
2185 else
2186 {
2187 /* Nothing to merge but change current entry */
2188 PartEntry->New = FALSE;
2189 PartEntry->Unpartitioned = TRUE;
2190 PartEntry->UnpartitionedOffset =
2191 PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
2192 PartEntry->UnpartitionedLength =
2193 PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
2194
2195 /* Wipe the partition table */
2196 RtlZeroMemory (&PartEntry->PartInfo,
2197 sizeof(PartEntry->PartInfo));
2198 }
2199
2200 DiskEntry->Modified = TRUE;
2201
2202 UpdatePartitionNumbers (DiskEntry);
2203
2204 AssignDriverLetters (List);
2205 }
2206
2207
2208 VOID
2209 CheckActiveBootPartition (PPARTLIST List)
2210 {
2211 PDISKENTRY DiskEntry;
2212 PPARTENTRY PartEntry;
2213
2214 /* Check for empty disk list */
2215 if (IsListEmpty (&List->DiskListHead))
2216 {
2217 List->ActiveBootDisk = NULL;
2218 List->ActiveBootPartition = NULL;
2219 return;
2220 }
2221
2222 #if 0
2223 if (List->ActiveBootDisk != NULL &&
2224 List->ActiveBootPartition != NULL)
2225 {
2226 /* We already have an active boot partition */
2227 return;
2228 }
2229 #endif
2230
2231 DiskEntry = CONTAINING_RECORD (List->DiskListHead.Flink,
2232 DISKENTRY,
2233 ListEntry);
2234
2235 /* Check for empty partition list */
2236 if (IsListEmpty (&DiskEntry->PartListHead))
2237 {
2238 List->ActiveBootDisk = NULL;
2239 List->ActiveBootPartition = NULL;
2240 return;
2241 }
2242
2243 PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
2244 PARTENTRY,
2245 ListEntry);
2246
2247 /* Set active boot partition */
2248 if ((DiskEntry->NewDisk == TRUE) ||
2249 (PartEntry->PartInfo[0].BootIndicator == FALSE &&
2250 PartEntry->PartInfo[1].BootIndicator == FALSE &&
2251 PartEntry->PartInfo[2].BootIndicator == FALSE &&
2252 PartEntry->PartInfo[3].BootIndicator == FALSE))
2253 {
2254 PartEntry->PartInfo[0].BootIndicator = TRUE;
2255 PartEntry->PartInfo[0].RewritePartition = TRUE;
2256 DiskEntry->Modified = TRUE;
2257 }
2258
2259 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
2260 List->ActiveBootDisk = DiskEntry;
2261 List->ActiveBootPartition = PartEntry;
2262 }
2263
2264
2265 BOOLEAN
2266 CheckForLinuxFdiskPartitions (PPARTLIST List)
2267 {
2268 PDISKENTRY DiskEntry;
2269 PPARTENTRY PartEntry;
2270 PLIST_ENTRY Entry1;
2271 PLIST_ENTRY Entry2;
2272 ULONG PartitionCount;
2273 ULONG i;
2274
2275 Entry1 = List->DiskListHead.Flink;
2276 while (Entry1 != &List->DiskListHead)
2277 {
2278 DiskEntry = CONTAINING_RECORD (Entry1,
2279 DISKENTRY,
2280 ListEntry);
2281
2282 Entry2 = DiskEntry->PartListHead.Flink;
2283 while (Entry2 != &DiskEntry->PartListHead)
2284 {
2285 PartEntry = CONTAINING_RECORD (Entry2,
2286 PARTENTRY,
2287 ListEntry);
2288
2289 if (PartEntry->Unpartitioned == FALSE)
2290 {
2291 PartitionCount = 0;
2292
2293 for (i = 0; i < 4; i++)
2294 {
2295 if (!IsContainerPartition (PartEntry->PartInfo[i].PartitionType) &&
2296 PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
2297 {
2298 PartitionCount++;
2299 }
2300 }
2301
2302 if (PartitionCount > 1)
2303 {
2304 return TRUE;
2305 }
2306 }
2307
2308 Entry2 = Entry2->Flink;
2309 }
2310
2311 Entry1 = Entry1->Flink;
2312 }
2313
2314 return FALSE;
2315 }
2316
2317
2318 BOOLEAN
2319 WritePartitionsToDisk (PPARTLIST List)
2320 {
2321 PDRIVE_LAYOUT_INFORMATION DriveLayout;
2322 OBJECT_ATTRIBUTES ObjectAttributes;
2323 IO_STATUS_BLOCK Iosb;
2324 WCHAR SrcPath[MAX_PATH];
2325 WCHAR DstPath[MAX_PATH];
2326 UNICODE_STRING Name;
2327 HANDLE FileHandle;
2328 PDISKENTRY DiskEntry1;
2329 PDISKENTRY DiskEntry2;
2330 PPARTENTRY PartEntry;
2331 PLIST_ENTRY Entry1;
2332 PLIST_ENTRY Entry2;
2333 ULONG PartitionCount;
2334 ULONG DriveLayoutSize;
2335 ULONG Index;
2336 NTSTATUS Status;
2337
2338 if (List == NULL)
2339 {
2340 return TRUE;
2341 }
2342
2343 Entry1 = List->DiskListHead.Flink;
2344 while (Entry1 != &List->DiskListHead)
2345 {
2346 DiskEntry1 = CONTAINING_RECORD (Entry1,
2347 DISKENTRY,
2348 ListEntry);
2349
2350 if (DiskEntry1->Modified == TRUE)
2351 {
2352 /* Count partitioned entries */
2353 PartitionCount = 0;
2354 Entry2 = DiskEntry1->PartListHead.Flink;
2355 while (Entry2 != &DiskEntry1->PartListHead)
2356 {
2357 PartEntry = CONTAINING_RECORD (Entry2,
2358 PARTENTRY,
2359 ListEntry);
2360 if (PartEntry->Unpartitioned == FALSE)
2361 {
2362 PartitionCount += 4;
2363 }
2364
2365 Entry2 = Entry2->Flink;
2366 }
2367 if (PartitionCount == 0)
2368 {
2369 DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
2370 ((4 - 1) * sizeof (PARTITION_INFORMATION));
2371 }
2372 else
2373 {
2374 DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
2375 ((PartitionCount - 1) * sizeof (PARTITION_INFORMATION));
2376 }
2377 DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap (ProcessHeap,
2378 0,
2379 DriveLayoutSize);
2380 if (DriveLayout == NULL)
2381 {
2382 DPRINT1 ("RtlAllocateHeap() failed\n");
2383 return FALSE;
2384 }
2385
2386 RtlZeroMemory (DriveLayout,
2387 DriveLayoutSize);
2388
2389 if (PartitionCount == 0)
2390 {
2391 /* delete all partitions in the mbr */
2392 DriveLayout->PartitionCount = 4;
2393 for (Index = 0; Index < 4; Index++)
2394 {
2395 DriveLayout->PartitionEntry[Index].RewritePartition = TRUE;
2396 }
2397 }
2398 else
2399 {
2400 DriveLayout->PartitionCount = PartitionCount;
2401
2402 Index = 0;
2403 Entry2 = DiskEntry1->PartListHead.Flink;
2404 while (Entry2 != &DiskEntry1->PartListHead)
2405 {
2406 PartEntry = CONTAINING_RECORD (Entry2,
2407 PARTENTRY,
2408 ListEntry);
2409 if (PartEntry->Unpartitioned == FALSE)
2410 {
2411 RtlCopyMemory (&DriveLayout->PartitionEntry[Index],
2412 &PartEntry->PartInfo[0],
2413 4 * sizeof (PARTITION_INFORMATION));
2414 Index += 4;
2415 }
2416
2417 Entry2 = Entry2->Flink;
2418 }
2419 }
2420 if (DiskEntry1->Signature == 0)
2421 {
2422 LARGE_INTEGER SystemTime;
2423 TIME_FIELDS TimeFields;
2424 PUCHAR Buffer;
2425 Buffer = (PUCHAR)&DiskEntry1->Signature;
2426
2427 while (1)
2428 {
2429 NtQuerySystemTime (&SystemTime);
2430 RtlTimeToTimeFields (&SystemTime, &TimeFields);
2431
2432 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
2433 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
2434 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
2435 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
2436
2437 if (DiskEntry1->Signature == 0)
2438 {
2439 continue;
2440 }
2441
2442 /* check if the signature already exist */
2443 /* FIXME:
2444 * Check also signatures from disks, which are
2445 * not visible (bootable) by the bios.
2446 */
2447 Entry2 = List->DiskListHead.Flink;
2448 while (Entry2 != &List->DiskListHead)
2449 {
2450 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
2451 if (DiskEntry1 != DiskEntry2 &&
2452 DiskEntry1->Signature == DiskEntry2->Signature)
2453 {
2454 break;
2455 }
2456 Entry2 = Entry2->Flink;
2457 }
2458 if (Entry2 == &List->DiskListHead)
2459 {
2460 break;
2461 }
2462 }
2463
2464 /* set one partition entry to dirty, this will update the signature */
2465 DriveLayout->PartitionEntry[0].RewritePartition = TRUE;
2466
2467 }
2468
2469 DriveLayout->Signature = DiskEntry1->Signature;
2470
2471
2472 swprintf (DstPath,
2473 L"\\Device\\Harddisk%d\\Partition0",
2474 DiskEntry1->DiskNumber);
2475 RtlInitUnicodeString (&Name,
2476 DstPath);
2477 InitializeObjectAttributes (&ObjectAttributes,
2478 &Name,
2479 0,
2480 NULL,
2481 NULL);
2482
2483 Status = NtOpenFile (&FileHandle,
2484 FILE_ALL_ACCESS,
2485 &ObjectAttributes,
2486 &Iosb,
2487 0,
2488 FILE_SYNCHRONOUS_IO_NONALERT);
2489
2490 if (!NT_SUCCESS (Status))
2491 {
2492 DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status);
2493 return FALSE;
2494 }
2495
2496 Status = NtDeviceIoControlFile (FileHandle,
2497 NULL,
2498 NULL,
2499 NULL,
2500 &Iosb,
2501 IOCTL_DISK_SET_DRIVE_LAYOUT,
2502 DriveLayout,
2503 DriveLayoutSize,
2504 NULL,
2505 0);
2506 if (!NT_SUCCESS (Status))
2507 {
2508 DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status);
2509 NtClose (FileHandle);
2510 return FALSE;
2511 }
2512
2513 RtlFreeHeap (ProcessHeap,
2514 0,
2515 DriveLayout);
2516
2517 NtClose (FileHandle);
2518
2519 /* Install MBR code if the disk is new */
2520 if (DiskEntry1->NewDisk == TRUE &&
2521 DiskEntry1->BiosDiskNumber == 0)
2522 {
2523 wcscpy (SrcPath, SourceRootPath.Buffer);
2524 wcscat (SrcPath, L"\\loader\\dosmbr.bin");
2525
2526 DPRINT ("Install MBR bootcode: %S ==> %S\n",
2527 SrcPath, DstPath);
2528
2529 /* Install MBR bootcode */
2530 Status = InstallMbrBootCodeToDisk (SrcPath,
2531 DstPath);
2532 if (!NT_SUCCESS (Status))
2533 {
2534 DPRINT1 ("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
2535 Status);
2536 return FALSE;
2537 }
2538
2539 DiskEntry1->NewDisk = FALSE;
2540 }
2541 }
2542
2543 Entry1 = Entry1->Flink;
2544 }
2545
2546 return TRUE;
2547 }
2548
2549 BOOL SetMountedDeviceValues(PPARTLIST List)
2550 {
2551 PLIST_ENTRY Entry1, Entry2;
2552 PDISKENTRY DiskEntry;
2553 PPARTENTRY PartEntry;
2554
2555 if (List == NULL)
2556 {
2557 return FALSE;
2558 }
2559
2560 Entry1 = List->DiskListHead.Flink;
2561 while (Entry1 != &List->DiskListHead)
2562 {
2563 DiskEntry = CONTAINING_RECORD (Entry1,
2564 DISKENTRY,
2565 ListEntry);
2566
2567 Entry2 = DiskEntry->PartListHead.Flink;
2568 while (Entry2 != &DiskEntry->PartListHead)
2569 {
2570 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
2571 if (!PartEntry->Unpartitioned && PartEntry->DriveLetter)
2572 {
2573 if (!SetMountedDeviceValue(PartEntry->DriveLetter, DiskEntry->Signature, PartEntry->PartInfo[0].StartingOffset))
2574 {
2575 return FALSE;
2576 }
2577 }
2578 Entry2 = Entry2->Flink;
2579 }
2580 Entry1 = Entry1->Flink;
2581 }
2582 return TRUE;
2583 }
2584
2585
2586
2587 /* EOF */