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