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