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