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