usetup: translate error codes, fix a typo
[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(*Int13Drives,
521 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
522 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
523 return STATUS_SUCCESS;
524 }
525 return STATUS_UNSUCCESSFUL;
526 }
527 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
528
529 static VOID
530 EnumerateBiosDiskEntries(PPARTLIST PartList)
531 {
532 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
533 WCHAR Name[120];
534 ULONG AdapterCount;
535 ULONG DiskCount;
536 NTSTATUS Status;
537 PCM_INT13_DRIVE_PARAMETER Int13Drives;
538 PBIOSDISKENTRY BiosDiskEntry;
539
540 memset(QueryTable, 0, sizeof(QueryTable));
541
542 QueryTable[1].Name = L"Configuration Data";
543 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
544 Int13Drives = NULL;
545 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
546 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
547 &QueryTable[1],
548 (PVOID)&Int13Drives,
549 NULL);
550 if (!NT_SUCCESS(Status))
551 {
552 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
553 return;
554 }
555
556 AdapterCount = 0;
557 while (1)
558 {
559 swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
560 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
561 Name,
562 &QueryTable[2],
563 NULL,
564 NULL);
565 if (!NT_SUCCESS(Status))
566 {
567 break;
568 }
569
570 swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
571 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
572 Name,
573 &QueryTable[2],
574 NULL,
575 NULL);
576 if (NT_SUCCESS(Status))
577 {
578 while (1)
579 {
580 swprintf(Name, L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount);
581 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
582 Name,
583 &QueryTable[2],
584 NULL,
585 NULL);
586 if (!NT_SUCCESS(Status))
587 {
588 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
589 return;
590 }
591
592 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount);
593 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
594 Name,
595 &QueryTable[2],
596 NULL,
597 NULL);
598 if (NT_SUCCESS(Status))
599 {
600 QueryTable[0].Name = L"Identifier";
601 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
602 QueryTable[1].Name = L"Configuration Data";
603 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
604 DiskCount = 0;
605 while (1)
606 {
607 BiosDiskEntry = (BIOSDISKENTRY*) RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
608 if (BiosDiskEntry == NULL)
609 {
610 break;
611 }
612 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount);
613 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
614 Name,
615 QueryTable,
616 (PVOID)BiosDiskEntry,
617 NULL);
618 if (!NT_SUCCESS(Status))
619 {
620 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
621 break;
622 }
623 BiosDiskEntry->DiskNumber = DiskCount;
624 BiosDiskEntry->Recognized = FALSE;
625
626 if (DiskCount < Int13Drives[0].NumberDrives)
627 {
628 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
629 }
630 else
631 {
632 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
633 }
634
635
636 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
637
638 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
639 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
640 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
641 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
642 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
643 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
644 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
645 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
646 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
647 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
648 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
649
650 DiskCount++;
651 }
652 }
653 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
654 return;
655 }
656 }
657 AdapterCount++;
658 }
659 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
660 }
661
662 static VOID
663 AddDiskToList (HANDLE FileHandle,
664 ULONG DiskNumber,
665 PPARTLIST List)
666 {
667 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
668 DISK_GEOMETRY DiskGeometry;
669 SCSI_ADDRESS ScsiAddress;
670 PDISKENTRY DiskEntry;
671 IO_STATUS_BLOCK Iosb;
672 NTSTATUS Status;
673 PPARTITION_SECTOR Mbr;
674 PULONG Buffer;
675 LARGE_INTEGER FileOffset;
676 WCHAR Identifier[20];
677 ULONG Checksum;
678 ULONG Signature;
679 ULONG i;
680 PLIST_ENTRY ListEntry;
681 PBIOSDISKENTRY BiosDiskEntry;
682
683 Status = NtDeviceIoControlFile (FileHandle,
684 NULL,
685 NULL,
686 NULL,
687 &Iosb,
688 IOCTL_DISK_GET_DRIVE_GEOMETRY,
689 NULL,
690 0,
691 &DiskGeometry,
692 sizeof(DISK_GEOMETRY));
693 if (!NT_SUCCESS (Status))
694 {
695 return;
696 }
697
698 if (DiskGeometry.MediaType != FixedMedia)
699 {
700 return;
701 }
702
703 Status = NtDeviceIoControlFile (FileHandle,
704 NULL,
705 NULL,
706 NULL,
707 &Iosb,
708 IOCTL_SCSI_GET_ADDRESS,
709 NULL,
710 0,
711 &ScsiAddress,
712 sizeof(SCSI_ADDRESS));
713 if (!NT_SUCCESS(Status))
714 {
715 return;
716 }
717
718 Mbr = (PARTITION_SECTOR*) RtlAllocateHeap(ProcessHeap,
719 0,
720 DiskGeometry.BytesPerSector);
721
722 if (Mbr == NULL)
723 {
724 return;
725 }
726
727 FileOffset.QuadPart = 0;
728 Status = NtReadFile(FileHandle,
729 NULL,
730 NULL,
731 NULL,
732 &Iosb,
733 (PVOID)Mbr,
734 DiskGeometry.BytesPerSector,
735 &FileOffset,
736 NULL);
737 if (!NT_SUCCESS(Status))
738 {
739 RtlFreeHeap(ProcessHeap,
740 0,
741 Mbr);
742 DPRINT1("NtReadFile failed, status=%x\n", Status);
743 return;
744 }
745 Signature = Mbr->Signature;
746
747 /* Calculate the MBR checksum */
748 Checksum = 0;
749 Buffer = (PULONG)Mbr;
750 for (i = 0; i < 128; i++)
751 {
752 Checksum += Buffer[i];
753 }
754 Checksum = ~Checksum + 1;
755
756 RtlFreeHeap (ProcessHeap,
757 0,
758 Mbr);
759
760 swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
761 DPRINT("Identifier: %S\n", Identifier);
762
763 DiskEntry = (PDISKENTRY)RtlAllocateHeap (ProcessHeap,
764 0,
765 sizeof(DISKENTRY));
766 if (DiskEntry == NULL)
767 {
768 return;
769 }
770
771 DiskEntry->Checksum = Checksum;
772 DiskEntry->Signature = Signature;
773 if (Signature == 0)
774 {
775 /* If we have no signature, set the disk to dirty. WritePartitionsToDisk creates a new signature */
776 DiskEntry->Modified = TRUE;
777 }
778 DiskEntry->BiosFound = FALSE;
779
780 ListEntry = List->BiosDiskListHead.Flink;
781 while(ListEntry != &List->BiosDiskListHead)
782 {
783 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
784 /* FIXME:
785 * Compare the size from bios and the reported size from driver.
786 * If we have more than one disk with a zero or with the same signatur
787 * we must create new signatures and reboot. After the reboot,
788 * it is possible to identify the disks.
789 */
790 if (BiosDiskEntry->Signature == Signature &&
791 BiosDiskEntry->Checksum == Checksum &&
792 !BiosDiskEntry->Recognized)
793 {
794 if (!DiskEntry->BiosFound)
795 {
796 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
797 DiskEntry->BiosFound = TRUE;
798 BiosDiskEntry->Recognized = TRUE;
799 }
800 else
801 {
802 }
803 }
804 ListEntry = ListEntry->Flink;
805 }
806
807 if (!DiskEntry->BiosFound)
808 {
809 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
810 return;
811 }
812
813 InitializeListHead (&DiskEntry->PartListHead);
814
815 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
816 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
817 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
818 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
819
820 DPRINT ("Cylinders %d\n", DiskEntry->Cylinders);
821 DPRINT ("TracksPerCylinder %d\n", DiskEntry->TracksPerCylinder);
822 DPRINT ("SectorsPerTrack %d\n", DiskEntry->SectorsPerTrack);
823 DPRINT ("BytesPerSector %d\n", DiskEntry->BytesPerSector);
824
825 DiskEntry->DiskSize =
826 DiskGeometry.Cylinders.QuadPart *
827 (ULONGLONG)DiskGeometry.TracksPerCylinder *
828 (ULONGLONG)DiskGeometry.SectorsPerTrack *
829 (ULONGLONG)DiskGeometry.BytesPerSector;
830 DiskEntry->CylinderSize =
831 (ULONGLONG)DiskGeometry.TracksPerCylinder *
832 (ULONGLONG)DiskGeometry.SectorsPerTrack *
833 (ULONGLONG)DiskGeometry.BytesPerSector;
834 DiskEntry->TrackSize =
835 (ULONGLONG)DiskGeometry.SectorsPerTrack *
836 (ULONGLONG)DiskGeometry.BytesPerSector;
837
838 DiskEntry->DiskNumber = DiskNumber;
839 DiskEntry->Port = ScsiAddress.PortNumber;
840 DiskEntry->Bus = ScsiAddress.PathId;
841 DiskEntry->Id = ScsiAddress.TargetId;
842
843 GetDriverName (DiskEntry);
844
845 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, BiosDiskNumber);
846
847 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap (ProcessHeap,
848 0,
849 8192);
850 if (LayoutBuffer == NULL)
851 {
852 return;
853 }
854
855 Status = NtDeviceIoControlFile (FileHandle,
856 NULL,
857 NULL,
858 NULL,
859 &Iosb,
860 IOCTL_DISK_GET_DRIVE_LAYOUT,
861 NULL,
862 0,
863 LayoutBuffer,
864 8192);
865 if (NT_SUCCESS (Status))
866 {
867 if (LayoutBuffer->PartitionCount == 0)
868 {
869 DiskEntry->NewDisk = TRUE;
870 }
871
872 AddPartitionToList (DiskNumber,
873 DiskEntry,
874 LayoutBuffer);
875
876 ScanForUnpartitionedDiskSpace (DiskEntry);
877 }
878
879 RtlFreeHeap (ProcessHeap,
880 0,
881 LayoutBuffer);
882 }
883
884
885 PPARTLIST
886 CreatePartitionList (SHORT Left,
887 SHORT Top,
888 SHORT Right,
889 SHORT Bottom)
890 {
891 PPARTLIST List;
892 OBJECT_ATTRIBUTES ObjectAttributes;
893 SYSTEM_DEVICE_INFORMATION Sdi;
894 IO_STATUS_BLOCK Iosb;
895 SIZE_T ReturnSize;
896 NTSTATUS Status;
897 ULONG DiskNumber;
898 WCHAR Buffer[MAX_PATH];
899 UNICODE_STRING Name;
900 HANDLE FileHandle;
901
902 List = (PPARTLIST)RtlAllocateHeap (ProcessHeap,
903 0,
904 sizeof (PARTLIST));
905 if (List == NULL)
906 return NULL;
907
908 List->Left = Left;
909 List->Top = Top;
910 List->Right = Right;
911 List->Bottom = Bottom;
912
913 List->Line = 0;
914
915 List->TopDisk = (ULONG)-1;
916 List->TopPartition = (ULONG)-1;
917
918 List->CurrentDisk = NULL;
919 List->CurrentPartition = NULL;
920
921 InitializeListHead (&List->DiskListHead);
922 InitializeListHead (&List->BiosDiskListHead);
923
924 EnumerateBiosDiskEntries(List);
925
926 Status = NtQuerySystemInformation (SystemDeviceInformation,
927 &Sdi,
928 sizeof(SYSTEM_DEVICE_INFORMATION),
929 &ReturnSize);
930 if (!NT_SUCCESS (Status))
931 {
932 RtlFreeHeap (ProcessHeap, 0, List);
933 return NULL;
934 }
935
936 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
937 {
938 swprintf (Buffer,
939 L"\\Device\\Harddisk%d\\Partition0",
940 DiskNumber);
941 RtlInitUnicodeString (&Name,
942 Buffer);
943
944 InitializeObjectAttributes (&ObjectAttributes,
945 &Name,
946 0,
947 NULL,
948 NULL);
949
950 Status = NtOpenFile (&FileHandle,
951 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
952 &ObjectAttributes,
953 &Iosb,
954 FILE_SHARE_READ,
955 FILE_SYNCHRONOUS_IO_NONALERT);
956 if (NT_SUCCESS(Status))
957 {
958 AddDiskToList (FileHandle,
959 DiskNumber,
960 List);
961
962 NtClose(FileHandle);
963 }
964 }
965
966 AssignDriverLetters (List);
967
968 List->TopDisk = 0;
969 List->TopPartition = 0;
970
971 /* Search for first usable disk and partition */
972 if (IsListEmpty (&List->DiskListHead))
973 {
974 List->CurrentDisk = NULL;
975 List->CurrentPartition = NULL;
976 }
977 else
978 {
979 List->CurrentDisk =
980 CONTAINING_RECORD (List->DiskListHead.Flink,
981 DISKENTRY,
982 ListEntry);
983
984 if (IsListEmpty (&List->CurrentDisk->PartListHead))
985 {
986 List->CurrentPartition = 0;
987 }
988 else
989 {
990 List->CurrentPartition =
991 CONTAINING_RECORD (List->CurrentDisk->PartListHead.Flink,
992 PARTENTRY,
993 ListEntry);
994 }
995 }
996
997 return List;
998 }
999
1000
1001 VOID
1002 DestroyPartitionList (PPARTLIST List)
1003 {
1004 PDISKENTRY DiskEntry;
1005 PBIOSDISKENTRY BiosDiskEntry;
1006 PPARTENTRY PartEntry;
1007 PLIST_ENTRY Entry;
1008
1009 /* Release disk and partition info */
1010 while (!IsListEmpty (&List->DiskListHead))
1011 {
1012 Entry = RemoveHeadList (&List->DiskListHead);
1013 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1014
1015 /* Release driver name */
1016 RtlFreeUnicodeString(&DiskEntry->DriverName);
1017
1018 /* Release partition array */
1019 while (!IsListEmpty (&DiskEntry->PartListHead))
1020 {
1021 Entry = RemoveHeadList (&DiskEntry->PartListHead);
1022 PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
1023
1024 RtlFreeHeap (ProcessHeap,
1025 0,
1026 PartEntry);
1027 }
1028
1029 /* Release disk entry */
1030 RtlFreeHeap (ProcessHeap, 0, DiskEntry);
1031 }
1032
1033 /* release the bios disk info */
1034 while(!IsListEmpty(&List->BiosDiskListHead))
1035 {
1036 Entry = RemoveHeadList(&List->BiosDiskListHead);
1037 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1038
1039 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1040 }
1041
1042 /* Release list head */
1043 RtlFreeHeap (ProcessHeap, 0, List);
1044 }
1045
1046
1047 static VOID
1048 PrintEmptyLine (PPARTLIST List)
1049 {
1050 COORD coPos;
1051 DWORD Written;
1052 USHORT Width;
1053 USHORT Height;
1054
1055 Width = List->Right - List->Left - 1;
1056 Height = List->Bottom - List->Top - 2;
1057
1058
1059 coPos.X = List->Left + 1;
1060 coPos.Y = List->Top + 1 + List->Line;
1061
1062 if (List->Line >= 0 && List->Line <= Height)
1063 {
1064 FillConsoleOutputAttribute (StdOutput,
1065 FOREGROUND_WHITE | BACKGROUND_BLUE,
1066 Width,
1067 coPos,
1068 &Written);
1069
1070 FillConsoleOutputCharacterA (StdOutput,
1071 ' ',
1072 Width,
1073 coPos,
1074 &Written);
1075 }
1076 List->Line++;
1077 }
1078
1079
1080 static VOID
1081 PrintPartitionData (PPARTLIST List,
1082 PDISKENTRY DiskEntry,
1083 PPARTENTRY PartEntry)
1084 {
1085 CHAR LineBuffer[128];
1086 COORD coPos;
1087 DWORD Written;
1088 USHORT Width;
1089 USHORT Height;
1090
1091 LARGE_INTEGER PartSize;
1092 PCHAR Unit;
1093 UCHAR Attribute;
1094 PCHAR PartType;
1095
1096 Width = List->Right - List->Left - 1;
1097 Height = List->Bottom - List->Top - 2;
1098
1099
1100 coPos.X = List->Left + 1;
1101 coPos.Y = List->Top + 1 + List->Line;
1102
1103 if (PartEntry->Unpartitioned == TRUE)
1104 {
1105 #if 0
1106 if (PartEntry->UnpartitionledLength >= 0x280000000ULL) /* 10 GB */
1107 {
1108 PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 29)) >> 30;
1109 Unit = "GB";
1110 }
1111 else
1112 #endif
1113 if (PartEntry->UnpartitionedLength >= 0xA00000ULL) /* 10 MB */
1114 {
1115 PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;
1116 Unit = "MB";
1117 }
1118 else
1119 {
1120 PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 9)) >> 10;
1121 Unit = "KB";
1122 }
1123
1124 sprintf (LineBuffer,
1125 " Unpartitioned space %6lu %s",
1126 PartSize.u.LowPart,
1127 Unit);
1128 }
1129 else
1130 {
1131 /* Determine partition type */
1132 PartType = NULL;
1133 if (PartEntry->New == TRUE)
1134 {
1135 PartType = "New (Unformatted)";
1136 }
1137 else if (PartEntry->Unpartitioned == FALSE)
1138 {
1139 if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
1140 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
1141 (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
1142 (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
1143 {
1144 PartType = "FAT";
1145 }
1146 else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
1147 (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
1148 {
1149 PartType = "FAT32";
1150 }
1151 else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
1152 {
1153 PartType = "NTFS"; /* FIXME: Not quite correct! */
1154 }
1155 }
1156
1157 #if 0
1158 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
1159 {
1160 PartSize.QuadPart = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
1161 Unit = "GB";
1162 }
1163 else
1164 #endif
1165 if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0xA00000LL) /* 10 MB */
1166 {
1167 PartSize.QuadPart = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
1168 Unit = "MB";
1169 }
1170 else
1171 {
1172 PartSize.QuadPart = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 9)) >> 10;
1173 Unit = "KB";
1174 }
1175
1176 if (PartType == NULL)
1177 {
1178 sprintf (LineBuffer,
1179 "%c%c Type %-3u %6lu %s",
1180 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1181 (PartEntry->DriveLetter == 0) ? '-' : ':',
1182 PartEntry->PartInfo[0].PartitionType,
1183 PartSize.u.LowPart,
1184 Unit);
1185 }
1186 else
1187 {
1188 sprintf (LineBuffer,
1189 "%c%c %-24s %6lu %s",
1190 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1191 (PartEntry->DriveLetter == 0) ? '-' : ':',
1192 PartType,
1193 PartSize.u.LowPart,
1194 Unit);
1195 }
1196 }
1197
1198 Attribute = (List->CurrentDisk == DiskEntry &&
1199 List->CurrentPartition == PartEntry) ?
1200 FOREGROUND_BLUE | BACKGROUND_WHITE :
1201 FOREGROUND_WHITE | BACKGROUND_BLUE;
1202
1203 if (List->Line >= 0 && List->Line <= Height)
1204 {
1205 FillConsoleOutputCharacterA (StdOutput,
1206 ' ',
1207 Width,
1208 coPos,
1209 &Written);
1210 }
1211 coPos.X += 4;
1212 Width -= 8;
1213 if (List->Line >= 0 && List->Line <= Height)
1214 {
1215 FillConsoleOutputAttribute (StdOutput,
1216 Attribute,
1217 Width,
1218 coPos,
1219 &Written);
1220 }
1221 coPos.X++;
1222 Width -= 2;
1223 if (List->Line >= 0 && List->Line <= Height)
1224 {
1225 WriteConsoleOutputCharacterA (StdOutput,
1226 LineBuffer,
1227 min (strlen (LineBuffer), Width),
1228 coPos,
1229 &Written);
1230 }
1231 List->Line++;
1232 }
1233
1234
1235 static VOID
1236 PrintDiskData (PPARTLIST List,
1237 PDISKENTRY DiskEntry)
1238 {
1239 PPARTENTRY PartEntry;
1240 CHAR LineBuffer[128];
1241 COORD coPos;
1242 DWORD Written;
1243 USHORT Width;
1244 USHORT Height;
1245 ULARGE_INTEGER DiskSize;
1246 PCHAR Unit;
1247
1248 Width = List->Right - List->Left - 1;
1249 Height = List->Bottom - List->Top - 2;
1250
1251
1252 coPos.X = List->Left + 1;
1253 coPos.Y = List->Top + 1 + List->Line;
1254
1255 #if 0
1256 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
1257 {
1258 DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 29)) >> 30;
1259 Unit = "GB";
1260 }
1261 else
1262 #endif
1263 {
1264 DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 19)) >> 20;
1265 if (DiskSize.QuadPart == 0)
1266 DiskSize.QuadPart = 1;
1267 Unit = "MB";
1268 }
1269
1270 if (DiskEntry->DriverName.Length > 0)
1271 {
1272 sprintf (LineBuffer,
1273 "%6lu %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %S",
1274 DiskSize.u.LowPart,
1275 Unit,
1276 DiskEntry->DiskNumber,
1277 DiskEntry->Port,
1278 DiskEntry->Bus,
1279 DiskEntry->Id,
1280 DiskEntry->DriverName.Buffer);
1281 }
1282 else
1283 {
1284 sprintf (LineBuffer,
1285 "%6lu %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
1286 DiskSize.u.LowPart,
1287 Unit,
1288 DiskEntry->DiskNumber,
1289 DiskEntry->Port,
1290 DiskEntry->Bus,
1291 DiskEntry->Id);
1292 }
1293 if (List->Line >= 0 && List->Line <= Height)
1294 {
1295 FillConsoleOutputAttribute (StdOutput,
1296 FOREGROUND_WHITE | BACKGROUND_BLUE,
1297 Width,
1298 coPos,
1299 &Written);
1300
1301 FillConsoleOutputCharacterA (StdOutput,
1302 ' ',
1303 Width,
1304 coPos,
1305 &Written);
1306 }
1307
1308 coPos.X++;
1309 if (List->Line >= 0 && List->Line <= Height)
1310 {
1311 WriteConsoleOutputCharacterA (StdOutput,
1312 LineBuffer,
1313 min ((USHORT)strlen (LineBuffer), Width - 2),
1314 coPos,
1315 &Written);
1316 }
1317 List->Line++;
1318
1319 /* Print separator line */
1320 PrintEmptyLine (List);
1321
1322 /* Print partition lines*/
1323 LIST_FOR_EACH(PartEntry, &DiskEntry->PartListHead, PARTENTRY, ListEntry)
1324 {
1325 /* Print disk entry */
1326 PrintPartitionData (List,
1327 DiskEntry,
1328 PartEntry);
1329 }
1330
1331 /* Print separator line */
1332 PrintEmptyLine (List);
1333 }
1334
1335
1336 VOID
1337 DrawPartitionList (PPARTLIST List)
1338 {
1339 PLIST_ENTRY Entry, Entry2;
1340 PDISKENTRY DiskEntry;
1341 PPARTENTRY PartEntry = NULL;
1342 COORD coPos;
1343 DWORD Written;
1344 SHORT i;
1345 SHORT CurrentDiskLine;
1346 SHORT CurrentPartLine;
1347 SHORT LastLine;
1348 BOOL CurrentPartLineFound = FALSE;
1349 BOOL CurrentDiskLineFound = FALSE;
1350
1351 /* Calculate the line of the current disk and partition */
1352 CurrentDiskLine = 0;
1353 CurrentPartLine = 0;
1354 LastLine = 0;
1355 Entry = List->DiskListHead.Flink;
1356 while (Entry != &List->DiskListHead)
1357 {
1358 DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
1359 LastLine += 2;
1360 if (CurrentPartLineFound == FALSE)
1361 {
1362 CurrentPartLine += 2;
1363 }
1364 Entry2 = DiskEntry->PartListHead.Flink;
1365 while (Entry2 != &DiskEntry->PartListHead)
1366 {
1367 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1368 if (PartEntry == List->CurrentPartition)
1369 {
1370 CurrentPartLineFound = TRUE;
1371 }
1372 Entry2 = Entry2->Flink;
1373 if (CurrentPartLineFound == FALSE)
1374 {
1375 CurrentPartLine++;
1376 }
1377 LastLine++;
1378 }
1379 if (DiskEntry == List->CurrentDisk)
1380 {
1381 CurrentDiskLineFound = TRUE;
1382 }
1383 Entry = Entry->Flink;
1384 if (Entry != &List->DiskListHead)
1385 {
1386 if (CurrentDiskLineFound == FALSE)
1387 {
1388 CurrentPartLine ++;
1389 CurrentDiskLine = CurrentPartLine;
1390 }
1391 LastLine++;
1392 }
1393 else
1394 {
1395 LastLine--;
1396 }
1397 }
1398
1399 /* If it possible, make the disk name visible */
1400 if (CurrentPartLine < List->Offset)
1401 {
1402 List->Offset = CurrentPartLine;
1403 }
1404 else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
1405 {
1406 List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
1407 }
1408 if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
1409 {
1410 List->Offset = CurrentDiskLine;
1411 }
1412
1413
1414 /* draw upper left corner */
1415 coPos.X = List->Left;
1416 coPos.Y = List->Top;
1417 FillConsoleOutputCharacterA (StdOutput,
1418 0xDA, // '+',
1419 1,
1420 coPos,
1421 &Written);
1422
1423 /* draw upper edge */
1424 coPos.X = List->Left + 1;
1425 coPos.Y = List->Top;
1426 if (List->Offset == 0)
1427 {
1428 FillConsoleOutputCharacterA (StdOutput,
1429 0xC4, // '-',
1430 List->Right - List->Left - 1,
1431 coPos,
1432 &Written);
1433 }
1434 else
1435 {
1436 FillConsoleOutputCharacterA (StdOutput,
1437 0xC4, // '-',
1438 List->Right - List->Left - 5,
1439 coPos,
1440 &Written);
1441 coPos.X = List->Right - 5;
1442 WriteConsoleOutputCharacterA (StdOutput,
1443 "(\x18)", // "(up)"
1444 3,
1445 coPos,
1446 &Written);
1447 coPos.X = List->Right - 2;
1448 FillConsoleOutputCharacterA (StdOutput,
1449 0xC4, // '-',
1450 2,
1451 coPos,
1452 &Written);
1453 }
1454
1455 /* draw upper right corner */
1456 coPos.X = List->Right;
1457 coPos.Y = List->Top;
1458 FillConsoleOutputCharacterA (StdOutput,
1459 0xBF, // '+',
1460 1,
1461 coPos,
1462 &Written);
1463
1464 /* draw left and right edge */
1465 for (i = List->Top + 1; i < List->Bottom; i++)
1466 {
1467 coPos.X = List->Left;
1468 coPos.Y = i;
1469 FillConsoleOutputCharacterA (StdOutput,
1470 0xB3, // '|',
1471 1,
1472 coPos,
1473 &Written);
1474
1475 coPos.X = List->Right;
1476 FillConsoleOutputCharacterA (StdOutput,
1477 0xB3, //'|',
1478 1,
1479 coPos,
1480 &Written);
1481 }
1482
1483 /* draw lower left corner */
1484 coPos.X = List->Left;
1485 coPos.Y = List->Bottom;
1486 FillConsoleOutputCharacterA (StdOutput,
1487 0xC0, // '+',
1488 1,
1489 coPos,
1490 &Written);
1491
1492 /* draw lower edge */
1493 coPos.X = List->Left + 1;
1494 coPos.Y = List->Bottom;
1495 if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
1496 {
1497 FillConsoleOutputCharacterA (StdOutput,
1498 0xC4, // '-',
1499 List->Right - List->Left - 1,
1500 coPos,
1501 &Written);
1502 }
1503 else
1504 {
1505 FillConsoleOutputCharacterA (StdOutput,
1506 0xC4, // '-',
1507 List->Right - List->Left - 5,
1508 coPos,
1509 &Written);
1510 coPos.X = List->Right - 5;
1511 WriteConsoleOutputCharacterA (StdOutput,
1512 "(\x19)", // "(down)"
1513 3,
1514 coPos,
1515 &Written);
1516 coPos.X = List->Right - 2;
1517 FillConsoleOutputCharacterA (StdOutput,
1518 0xC4, // '-',
1519 2,
1520 coPos,
1521 &Written);
1522 }
1523
1524 /* draw lower right corner */
1525 coPos.X = List->Right;
1526 coPos.Y = List->Bottom;
1527 FillConsoleOutputCharacterA (StdOutput,
1528 0xD9, // '+',
1529 1,
1530 coPos,
1531 &Written);
1532
1533 /* print list entries */
1534 List->Line = - List->Offset;
1535
1536 LIST_FOR_EACH(DiskEntry, &List->DiskListHead, DISKENTRY, ListEntry)
1537 {
1538 /* Print disk entry */
1539 PrintDiskData (List,
1540 DiskEntry);
1541 }
1542 }
1543
1544
1545 DWORD
1546 SelectPartition(PPARTLIST List, ULONG DiskNumber, ULONG PartitionNumber)
1547 {
1548 PDISKENTRY DiskEntry;
1549 PPARTENTRY PartEntry;
1550 PLIST_ENTRY Entry1;
1551 PLIST_ENTRY Entry2;
1552 ULONG i;
1553
1554 /* Check for empty disks */
1555 if (IsListEmpty (&List->DiskListHead))
1556 return FALSE;
1557
1558 /* Check for first usable entry on next disk */
1559 Entry1 = List->CurrentDisk->ListEntry.Flink;
1560 while (Entry1 != &List->DiskListHead)
1561 {
1562 DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
1563
1564 if (DiskEntry->DiskNumber == DiskNumber)
1565 {
1566 Entry2 = DiskEntry->PartListHead.Flink;
1567 while (Entry2 != &DiskEntry->PartListHead)
1568 {
1569 PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
1570
1571 for (i = 0; i < 4; i++)
1572 {
1573 if (PartEntry->PartInfo[i].PartitionNumber == PartitionNumber)
1574 {
1575 List->CurrentDisk = DiskEntry;
1576 List->CurrentPartition = PartEntry;
1577 DrawPartitionList (List);
1578 return TRUE;
1579 }
1580 }
1581 Entry2 = Entry2->Flink;
1582 }
1583 return FALSE;
1584 }
1585 Entry1 = Entry1->Flink;
1586 }
1587 return FALSE;
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 */