xref: /reactos/base/system/diskpart/partlist.c (revision 279107d5)
1 /*
2  * PROJECT:         ReactOS DiskPart
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            base/system/diskpart/partlist.c
5  * PURPOSE:         Manages all the partitions of the OS in an interactive way.
6  * PROGRAMMERS:     Eric Kohl
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "diskpart.h"
12 #include <ntddscsi.h>
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 #define InsertAscendingList(ListHead, NewEntry, Type, ListEntryField, SortField)\
18 {\
19   PLIST_ENTRY current;\
20 \
21   current = (ListHead)->Flink;\
22   while (current != (ListHead))\
23   {\
24     if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >=\
25         (NewEntry)->SortField)\
26     {\
27       break;\
28     }\
29     current = current->Flink;\
30   }\
31 \
32   InsertTailList(current, &((NewEntry)->ListEntryField));\
33 }
34 
35 /* We have to define it there, because it is not in the MS DDK */
36 #define PARTITION_LINUX 0x83
37 
38 #define PARTITION_TBL_SIZE 4
39 
40 #include <pshpack1.h>
41 
42 typedef struct _PARTITION
43 {
44     unsigned char   BootFlags;        /* bootable?  0=no, 128=yes  */
45     unsigned char   StartingHead;     /* beginning head number */
46     unsigned char   StartingSector;   /* beginning sector number */
47     unsigned char   StartingCylinder; /* 10 bit nmbr, with high 2 bits put in begsect */
48     unsigned char   PartitionType;    /* Operating System type indicator code */
49     unsigned char   EndingHead;       /* ending head number */
50     unsigned char   EndingSector;     /* ending sector number */
51     unsigned char   EndingCylinder;   /* also a 10 bit nmbr, with same high 2 bit trick */
52     unsigned int  StartingBlock;      /* first sector relative to start of disk */
53     unsigned int  SectorCount;        /* number of sectors in partition */
54 } PARTITION, *PPARTITION;
55 
56 typedef struct _PARTITION_SECTOR
57 {
58     UCHAR BootCode[440];                     /* 0x000 */
59     ULONG Signature;                         /* 0x1B8 */
60     UCHAR Reserved[2];                       /* 0x1BC */
61     PARTITION Partition[PARTITION_TBL_SIZE]; /* 0x1BE */
62     USHORT Magic;                            /* 0x1FE */
63 } PARTITION_SECTOR, *PPARTITION_SECTOR;
64 
65 #include <poppack.h>
66 
67 
68 /* GLOBALS ********************************************************************/
69 
70 LIST_ENTRY DiskListHead;
71 LIST_ENTRY BiosDiskListHead;
72 
73 PDISKENTRY CurrentDisk = NULL;
74 PPARTENTRY CurrentPartition = NULL;
75 
76 
77 /* FUNCTIONS ******************************************************************/
78 
79 ULONGLONG
80 AlignDown(
81     IN ULONGLONG Value,
82     IN ULONG Alignment)
83 {
84     ULONGLONG Temp;
85 
86     Temp = Value / Alignment;
87 
88     return Temp * Alignment;
89 }
90 
91 static
92 VOID
93 GetDriverName(
94     PDISKENTRY DiskEntry)
95 {
96     RTL_QUERY_REGISTRY_TABLE QueryTable[2];
97     WCHAR KeyName[32];
98     NTSTATUS Status;
99 
100     RtlInitUnicodeString(&DiskEntry->DriverName,
101                          NULL);
102 
103     swprintf(KeyName,
104              L"\\Scsi\\Scsi Port %lu",
105              DiskEntry->Port);
106 
107     RtlZeroMemory(&QueryTable,
108                   sizeof(QueryTable));
109 
110     QueryTable[0].Name = L"Driver";
111     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
112     QueryTable[0].EntryContext = &DiskEntry->DriverName;
113 
114     Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
115                                     KeyName,
116                                     QueryTable,
117                                     NULL,
118                                     NULL);
119     if (!NT_SUCCESS(Status))
120     {
121         DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
122     }
123 }
124 
125 static
126 NTSTATUS
127 NTAPI
128 DiskIdentifierQueryRoutine(
129     PWSTR ValueName,
130     ULONG ValueType,
131     PVOID ValueData,
132     ULONG ValueLength,
133     PVOID Context,
134     PVOID EntryContext)
135 {
136     PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
137     UNICODE_STRING NameU;
138 
139     if (ValueType == REG_SZ &&
140         ValueLength == 20 * sizeof(WCHAR))
141     {
142         NameU.Buffer = (PWCHAR)ValueData;
143         NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
144         RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
145 
146         NameU.Buffer = (PWCHAR)ValueData + 9;
147         RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
148 
149         return STATUS_SUCCESS;
150     }
151 
152     return STATUS_UNSUCCESSFUL;
153 }
154 
155 static
156 NTSTATUS
157 NTAPI
158 DiskConfigurationDataQueryRoutine(
159     PWSTR ValueName,
160     ULONG ValueType,
161     PVOID ValueData,
162     ULONG ValueLength,
163     PVOID Context,
164     PVOID EntryContext)
165 {
166     PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
167     PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
168     PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
169     ULONG i;
170 
171     if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
172         ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
173         return STATUS_UNSUCCESSFUL;
174 
175     FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
176 
177     /* Hm. Version and Revision are not set on Microsoft Windows XP... */
178 #if 0
179     if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
180         FullResourceDescriptor->PartialResourceList.Revision != 1)
181         return STATUS_UNSUCCESSFUL;
182 #endif
183 
184     for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
185     {
186         if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
187             FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
188             continue;
189 
190         DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
191         BiosDiskEntry->DiskGeometry = *DiskGeometry;
192 
193         return STATUS_SUCCESS;
194     }
195 
196     return STATUS_UNSUCCESSFUL;
197 }
198 
199 static
200 NTSTATUS
201 NTAPI
202 SystemConfigurationDataQueryRoutine(
203     PWSTR ValueName,
204     ULONG ValueType,
205     PVOID ValueData,
206     ULONG ValueLength,
207     PVOID Context,
208     PVOID EntryContext)
209 {
210     PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
211     PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
212     ULONG i;
213 
214     if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
215         ValueLength < sizeof (CM_FULL_RESOURCE_DESCRIPTOR))
216         return STATUS_UNSUCCESSFUL;
217 
218     FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
219 
220     /* Hm. Version and Revision are not set on Microsoft Windows XP... */
221 #if 0
222     if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
223         FullResourceDescriptor->PartialResourceList.Revision != 1)
224         return STATUS_UNSUCCESSFUL;
225 #endif
226 
227     for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
228     {
229         if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
230             FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
231             continue;
232 
233         *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(RtlGetProcessHeap(), 0,
234                        FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
235         if (*Int13Drives == NULL)
236             return STATUS_NO_MEMORY;
237 
238         memcpy(*Int13Drives,
239                &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
240                FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
241         return STATUS_SUCCESS;
242     }
243 
244     return STATUS_UNSUCCESSFUL;
245 }
246 
247 
248 #define ROOT_NAME   L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
249 
250 static
251 VOID
252 EnumerateBiosDiskEntries(VOID)
253 {
254     RTL_QUERY_REGISTRY_TABLE QueryTable[3];
255     WCHAR Name[120];
256     ULONG AdapterCount;
257     ULONG DiskCount;
258     NTSTATUS Status;
259     PCM_INT13_DRIVE_PARAMETER Int13Drives;
260     PBIOSDISKENTRY BiosDiskEntry;
261 
262     memset(QueryTable, 0, sizeof(QueryTable));
263 
264     QueryTable[1].Name = L"Configuration Data";
265     QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
266     Int13Drives = NULL;
267     Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
268                                     L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
269                                     &QueryTable[1],
270                                     (PVOID)&Int13Drives,
271                                     NULL);
272     if (!NT_SUCCESS(Status))
273     {
274         DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
275         return;
276     }
277 
278     AdapterCount = 0;
279     while (1)
280     {
281         swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
282         Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
283                                         Name,
284                                         &QueryTable[2],
285                                         NULL,
286                                         NULL);
287         if (!NT_SUCCESS(Status))
288         {
289             break;
290         }
291 
292         swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
293         Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
294                                         Name,
295                                         &QueryTable[2],
296                                         NULL,
297                                         NULL);
298         if (NT_SUCCESS(Status))
299         {
300             while (1)
301             {
302                 swprintf(Name, L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount);
303                 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
304                                                 Name,
305                                                 &QueryTable[2],
306                                                 NULL,
307                                                 NULL);
308                 if (!NT_SUCCESS(Status))
309                 {
310                     RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives);
311                     return;
312                 }
313 
314                 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount);
315                 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
316                                                 Name,
317                                                 &QueryTable[2],
318                                                 NULL,
319                                                 NULL);
320                 if (NT_SUCCESS(Status))
321                 {
322                     QueryTable[0].Name = L"Identifier";
323                     QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
324                     QueryTable[1].Name = L"Configuration Data";
325                     QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
326 
327                     DiskCount = 0;
328                     while (1)
329                     {
330                         BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
331                         if (BiosDiskEntry == NULL)
332                         {
333                             break;
334                         }
335 
336                         swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount);
337                         Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
338                                                         Name,
339                                                         QueryTable,
340                                                         (PVOID)BiosDiskEntry,
341                                                         NULL);
342                         if (!NT_SUCCESS(Status))
343                         {
344                             RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry);
345                             break;
346                         }
347 
348                         BiosDiskEntry->DiskNumber = DiskCount;
349                         BiosDiskEntry->Recognized = FALSE;
350 
351                         if (DiskCount < Int13Drives[0].NumberDrives)
352                         {
353                             BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
354                         }
355                         else
356                         {
357                             DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
358                         }
359 
360                         InsertTailList(&BiosDiskListHead, &BiosDiskEntry->ListEntry);
361 
362                         DPRINT("DiskNumber:        %lu\n", BiosDiskEntry->DiskNumber);
363                         DPRINT("Signature:         %08lx\n", BiosDiskEntry->Signature);
364                         DPRINT("Checksum:          %08lx\n", BiosDiskEntry->Checksum);
365                         DPRINT("BytesPerSector:    %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
366                         DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
367                         DPRINT("NumberOfHeads:     %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
368                         DPRINT("DriveSelect:       %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
369                         DPRINT("MaxCylinders:      %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
370                         DPRINT("SectorsPerTrack:   %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
371                         DPRINT("MaxHeads:          %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
372                         DPRINT("NumberDrives:      %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
373 
374                         DiskCount++;
375                     }
376                 }
377 
378                 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives);
379                 return;
380             }
381         }
382 
383         AdapterCount++;
384     }
385 
386     RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives);
387 }
388 
389 
390 static
391 VOID
392 AddPartitionToDisk(
393     ULONG DiskNumber,
394     PDISKENTRY DiskEntry,
395     ULONG PartitionIndex,
396     BOOLEAN LogicalPartition)
397 {
398     PPARTITION_INFORMATION PartitionInfo;
399     PPARTENTRY PartEntry;
400 
401     PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
402     if (PartitionInfo->PartitionType == 0 ||
403         (LogicalPartition == TRUE && IsContainerPartition(PartitionInfo->PartitionType)))
404         return;
405 
406     PartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
407                                 HEAP_ZERO_MEMORY,
408                                 sizeof(PARTENTRY));
409     if (PartEntry == NULL)
410     {
411         return;
412     }
413 
414     PartEntry->DiskEntry = DiskEntry;
415 
416     PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
417     PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
418 
419     PartEntry->BootIndicator = PartitionInfo->BootIndicator;
420     PartEntry->PartitionType = PartitionInfo->PartitionType;
421     PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
422 
423     PartEntry->LogicalPartition = LogicalPartition;
424     PartEntry->IsPartitioned = TRUE;
425     PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
426     PartEntry->PartitionIndex = PartitionIndex;
427 
428     if (IsContainerPartition(PartEntry->PartitionType))
429     {
430         PartEntry->FormatState = Unformatted;
431 
432         if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
433             DiskEntry->ExtendedPartition = PartEntry;
434     }
435     else if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
436              (PartEntry->PartitionType == PARTITION_FAT_16) ||
437              (PartEntry->PartitionType == PARTITION_HUGE) ||
438              (PartEntry->PartitionType == PARTITION_XINT13) ||
439              (PartEntry->PartitionType == PARTITION_FAT32) ||
440              (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
441     {
442 #if 0
443         if (CheckFatFormat())
444         {
445             PartEntry->FormatState = Preformatted;
446         }
447         else
448         {
449             PartEntry->FormatState = Unformatted;
450         }
451 #endif
452         PartEntry->FormatState = Preformatted;
453     }
454     else if (PartEntry->PartitionType == PARTITION_LINUX)
455     {
456 #if 0
457         if (CheckExt2Format())
458         {
459             PartEntry->FormatState = Preformatted;
460         }
461         else
462         {
463             PartEntry->FormatState = Unformatted;
464         }
465 #endif
466         PartEntry->FormatState = Preformatted;
467     }
468     else if (PartEntry->PartitionType == PARTITION_IFS)
469     {
470 #if 0
471         if (CheckNtfsFormat())
472         {
473             PartEntry->FormatState = Preformatted;
474         }
475         else if (CheckHpfsFormat())
476         {
477             PartEntry->FormatState = Preformatted;
478         }
479         else
480         {
481             PartEntry->FormatState = Unformatted;
482         }
483 #endif
484         PartEntry->FormatState = Preformatted;
485     }
486     else
487     {
488         PartEntry->FormatState = UnknownFormat;
489     }
490 
491     if (LogicalPartition)
492         InsertTailList(&DiskEntry->LogicalPartListHead,
493                        &PartEntry->ListEntry);
494     else
495         InsertTailList(&DiskEntry->PrimaryPartListHead,
496                        &PartEntry->ListEntry);
497 }
498 
499 
500 static
501 VOID
502 ScanForUnpartitionedDiskSpace(
503     PDISKENTRY DiskEntry)
504 {
505     ULONGLONG LastStartSector;
506     ULONGLONG LastSectorCount;
507     ULONGLONG LastUnusedSectorCount;
508     PPARTENTRY PartEntry;
509     PPARTENTRY NewPartEntry;
510     PLIST_ENTRY Entry;
511 
512     DPRINT("ScanForUnpartitionedDiskSpace()\n");
513 
514     if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
515     {
516         DPRINT1("No primary partition!\n");
517 
518         /* Create a partition table that represents the empty disk */
519         NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
520                                        HEAP_ZERO_MEMORY,
521                                        sizeof(PARTENTRY));
522         if (NewPartEntry == NULL)
523             return;
524 
525         NewPartEntry->DiskEntry = DiskEntry;
526 
527         NewPartEntry->IsPartitioned = FALSE;
528         NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment;
529         NewPartEntry->SectorCount.QuadPart = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) -
530                                              NewPartEntry->StartSector.QuadPart;
531 
532         DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
533         DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
534         DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
535 
536         NewPartEntry->FormatState = Unformatted;
537 
538         InsertTailList(&DiskEntry->PrimaryPartListHead,
539                        &NewPartEntry->ListEntry);
540 
541         return;
542     }
543 
544     /* Start partition at head 1, cylinder 0 */
545     LastStartSector = DiskEntry->SectorAlignment;
546     LastSectorCount = 0ULL;
547     LastUnusedSectorCount = 0ULL;
548 
549     Entry = DiskEntry->PrimaryPartListHead.Flink;
550     while (Entry != &DiskEntry->PrimaryPartListHead)
551     {
552         PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
553 
554         if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
555             PartEntry->SectorCount.QuadPart != 0ULL)
556         {
557             LastUnusedSectorCount =
558                 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
559 
560             if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
561                 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
562             {
563                 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
564 
565                 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
566                                                HEAP_ZERO_MEMORY,
567                                                sizeof(PARTENTRY));
568                 if (NewPartEntry == NULL)
569                     return;
570 
571                 NewPartEntry->DiskEntry = DiskEntry;
572 
573                 NewPartEntry->IsPartitioned = FALSE;
574                 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
575                 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
576                                                      NewPartEntry->StartSector.QuadPart;
577 
578                 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
579                 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
580                 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
581 
582                 NewPartEntry->FormatState = Unformatted;
583 
584                 /* Insert the table into the list */
585                 InsertTailList(&PartEntry->ListEntry,
586                                &NewPartEntry->ListEntry);
587             }
588 
589             LastStartSector = PartEntry->StartSector.QuadPart;
590             LastSectorCount = PartEntry->SectorCount.QuadPart;
591         }
592 
593         Entry = Entry->Flink;
594     }
595 
596     /* Check for trailing unpartitioned disk space */
597     if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
598     {
599         LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
600 
601         if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
602         {
603             DPRINT1("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
604 
605             NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
606                                            HEAP_ZERO_MEMORY,
607                                            sizeof(PARTENTRY));
608             if (NewPartEntry == NULL)
609                 return;
610 
611             NewPartEntry->DiskEntry = DiskEntry;
612 
613             NewPartEntry->IsPartitioned = FALSE;
614             NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
615             NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
616                                                  NewPartEntry->StartSector.QuadPart;
617 
618             DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
619             DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
620             DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
621 
622             NewPartEntry->FormatState = Unformatted;
623 
624             /* Append the table to the list */
625             InsertTailList(&DiskEntry->PrimaryPartListHead,
626                            &NewPartEntry->ListEntry);
627         }
628     }
629 
630     if (DiskEntry->ExtendedPartition != NULL)
631     {
632         if (IsListEmpty(&DiskEntry->LogicalPartListHead))
633         {
634             DPRINT1("No logical partition!\n");
635 
636             /* Create a partition table entry that represents the empty extended partition */
637             NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
638                                            HEAP_ZERO_MEMORY,
639                                            sizeof(PARTENTRY));
640             if (NewPartEntry == NULL)
641                 return;
642 
643             NewPartEntry->DiskEntry = DiskEntry;
644             NewPartEntry->LogicalPartition = TRUE;
645 
646             NewPartEntry->IsPartitioned = FALSE;
647             NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
648             NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
649 
650             DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
651             DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
652             DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
653 
654             NewPartEntry->FormatState = Unformatted;
655 
656             InsertTailList(&DiskEntry->LogicalPartListHead,
657                            &NewPartEntry->ListEntry);
658 
659             return;
660         }
661 
662         /* Start partition at head 1, cylinder 0 */
663         LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
664         LastSectorCount = 0ULL;
665         LastUnusedSectorCount = 0ULL;
666 
667         Entry = DiskEntry->LogicalPartListHead.Flink;
668         while (Entry != &DiskEntry->LogicalPartListHead)
669         {
670             PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
671 
672             if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
673                 PartEntry->SectorCount.QuadPart != 0ULL)
674             {
675                 LastUnusedSectorCount =
676                     PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
677 
678                 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
679                     LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
680                 {
681                     DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
682 
683                     NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
684                                                    HEAP_ZERO_MEMORY,
685                                                    sizeof(PARTENTRY));
686                     if (NewPartEntry == NULL)
687                         return;
688 
689                     NewPartEntry->DiskEntry = DiskEntry;
690                     NewPartEntry->LogicalPartition = TRUE;
691 
692                     NewPartEntry->IsPartitioned = FALSE;
693                     NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
694                     NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
695                                                          NewPartEntry->StartSector.QuadPart;
696 
697                     DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
698                     DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
699                     DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
700 
701                     NewPartEntry->FormatState = Unformatted;
702 
703                     /* Insert the table into the list */
704                     InsertTailList(&PartEntry->ListEntry,
705                                    &NewPartEntry->ListEntry);
706                 }
707 
708                 LastStartSector = PartEntry->StartSector.QuadPart;
709                 LastSectorCount = PartEntry->SectorCount.QuadPart;
710             }
711 
712             Entry = Entry->Flink;
713         }
714 
715         /* Check for trailing unpartitioned disk space */
716         if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
717         {
718             LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
719                                               DiskEntry->SectorAlignment);
720 
721             if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
722             {
723                 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
724 
725                 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
726                                                HEAP_ZERO_MEMORY,
727                                                sizeof(PARTENTRY));
728                 if (NewPartEntry == NULL)
729                     return;
730 
731                 NewPartEntry->DiskEntry = DiskEntry;
732                 NewPartEntry->LogicalPartition = TRUE;
733 
734                 NewPartEntry->IsPartitioned = FALSE;
735                 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
736                 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
737                                                      NewPartEntry->StartSector.QuadPart;
738 
739                 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
740                 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
741                 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
742 
743                 NewPartEntry->FormatState = Unformatted;
744 
745                 /* Append the table to the list */
746                 InsertTailList(&DiskEntry->LogicalPartListHead,
747                                &NewPartEntry->ListEntry);
748             }
749         }
750     }
751 
752     DPRINT("ScanForUnpartitionedDiskSpace() done\n");
753 }
754 
755 
756 static
757 VOID
758 AddDiskToList(
759     HANDLE FileHandle,
760     ULONG DiskNumber)
761 {
762     DISK_GEOMETRY DiskGeometry;
763     SCSI_ADDRESS ScsiAddress;
764     PDISKENTRY DiskEntry;
765     IO_STATUS_BLOCK Iosb;
766     NTSTATUS Status;
767     PPARTITION_SECTOR Mbr;
768     PULONG Buffer;
769     LARGE_INTEGER FileOffset;
770     WCHAR Identifier[20];
771     ULONG Checksum;
772     ULONG Signature;
773     ULONG i;
774     PLIST_ENTRY ListEntry;
775     PBIOSDISKENTRY BiosDiskEntry;
776     ULONG LayoutBufferSize;
777     PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
778 
779     Status = NtDeviceIoControlFile(FileHandle,
780                                    NULL,
781                                    NULL,
782                                    NULL,
783                                    &Iosb,
784                                    IOCTL_DISK_GET_DRIVE_GEOMETRY,
785                                    NULL,
786                                    0,
787                                    &DiskGeometry,
788                                    sizeof(DISK_GEOMETRY));
789     if (!NT_SUCCESS(Status))
790     {
791         return;
792     }
793 
794     if (DiskGeometry.MediaType != FixedMedia &&
795         DiskGeometry.MediaType != RemovableMedia)
796     {
797         return;
798     }
799 
800     Status = NtDeviceIoControlFile(FileHandle,
801                                    NULL,
802                                    NULL,
803                                    NULL,
804                                    &Iosb,
805                                    IOCTL_SCSI_GET_ADDRESS,
806                                    NULL,
807                                    0,
808                                    &ScsiAddress,
809                                    sizeof(SCSI_ADDRESS));
810     if (!NT_SUCCESS(Status))
811     {
812         return;
813     }
814 
815     Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(RtlGetProcessHeap(),
816                                              0,
817                                              DiskGeometry.BytesPerSector);
818     if (Mbr == NULL)
819     {
820         return;
821     }
822 
823     FileOffset.QuadPart = 0;
824     Status = NtReadFile(FileHandle,
825                         NULL,
826                         NULL,
827                         NULL,
828                         &Iosb,
829                         (PVOID)Mbr,
830                         DiskGeometry.BytesPerSector,
831                         &FileOffset,
832                         NULL);
833     if (!NT_SUCCESS(Status))
834     {
835         RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr);
836         DPRINT1("NtReadFile failed, status=%x\n", Status);
837         return;
838     }
839     Signature = Mbr->Signature;
840 
841     /* Calculate the MBR checksum */
842     Checksum = 0;
843     Buffer = (PULONG)Mbr;
844     for (i = 0; i < 128; i++)
845     {
846         Checksum += Buffer[i];
847     }
848     Checksum = ~Checksum + 1;
849 
850     swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
851     DPRINT("Identifier: %S\n", Identifier);
852 
853     DiskEntry = RtlAllocateHeap(RtlGetProcessHeap(),
854                                 HEAP_ZERO_MEMORY,
855                                 sizeof(DISKENTRY));
856     if (DiskEntry == NULL)
857     {
858         return;
859     }
860 
861 //    DiskEntry->Checksum = Checksum;
862 //    DiskEntry->Signature = Signature;
863     DiskEntry->BiosFound = FALSE;
864 
865     /* Check if this disk has a valid MBR */
866     if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0)
867         DiskEntry->NoMbr = TRUE;
868     else
869         DiskEntry->NoMbr = FALSE;
870 
871     /* Free Mbr sector buffer */
872     RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr);
873 
874     ListEntry = BiosDiskListHead.Flink;
875     while (ListEntry != &BiosDiskListHead)
876     {
877         BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
878         /* FIXME:
879          *   Compare the size from bios and the reported size from driver.
880          *   If we have more than one disk with a zero or with the same signatur
881          *   we must create new signatures and reboot. After the reboot,
882          *   it is possible to identify the disks.
883          */
884         if (BiosDiskEntry->Signature == Signature &&
885             BiosDiskEntry->Checksum == Checksum &&
886             !BiosDiskEntry->Recognized)
887         {
888             if (!DiskEntry->BiosFound)
889             {
890                 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
891                 DiskEntry->BiosFound = TRUE;
892                 BiosDiskEntry->Recognized = TRUE;
893             }
894             else
895             {
896             }
897         }
898         ListEntry = ListEntry->Flink;
899     }
900 
901     if (!DiskEntry->BiosFound)
902     {
903 #if 0
904         RtlFreeHeap(ProcessHeap, 0, DiskEntry);
905         return;
906 #else
907         DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
908 #endif
909     }
910 
911     InitializeListHead(&DiskEntry->PrimaryPartListHead);
912     InitializeListHead(&DiskEntry->LogicalPartListHead);
913 
914     DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
915     DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
916     DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
917     DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
918 
919     DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
920     DPRINT("TracksPerCylinder %I64u\n", DiskEntry->TracksPerCylinder);
921     DPRINT("SectorsPerTrack %I64u\n", DiskEntry->SectorsPerTrack);
922     DPRINT("BytesPerSector %I64u\n", DiskEntry->BytesPerSector);
923 
924     DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
925                                       (ULONGLONG)DiskGeometry.TracksPerCylinder *
926                                       (ULONGLONG)DiskGeometry.SectorsPerTrack;
927 
928     DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
929     DiskEntry->CylinderAlignment = DiskGeometry.SectorsPerTrack * DiskGeometry.TracksPerCylinder;
930 
931     DPRINT1("SectorCount: %I64u\n", DiskEntry->SectorCount);
932     DPRINT1("SectorAlignment: %lu\n", DiskEntry->SectorAlignment);
933     DPRINT1("CylinderAlignment: %lu\n", DiskEntry->CylinderAlignment);
934 
935     DiskEntry->DiskNumber = DiskNumber;
936     DiskEntry->Port = ScsiAddress.PortNumber;
937     DiskEntry->Bus = ScsiAddress.PathId;
938     DiskEntry->Id = ScsiAddress.TargetId;
939 
940     GetDriverName(DiskEntry);
941 
942     InsertAscendingList(&DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
943 
944     /* Allocate a layout buffer with 4 partition entries first */
945     LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
946                        ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
947     DiskEntry->LayoutBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
948                                               HEAP_ZERO_MEMORY,
949                                               LayoutBufferSize);
950     if (DiskEntry->LayoutBuffer == NULL)
951     {
952         DPRINT1("Failed to allocate the disk layout buffer!\n");
953         return;
954     }
955 
956     for (;;)
957     {
958         DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
959         Status = NtDeviceIoControlFile(FileHandle,
960                                        NULL,
961                                        NULL,
962                                        NULL,
963                                        &Iosb,
964                                        IOCTL_DISK_GET_DRIVE_LAYOUT,
965                                        NULL,
966                                        0,
967                                        DiskEntry->LayoutBuffer,
968                                        LayoutBufferSize);
969         if (NT_SUCCESS(Status))
970             break;
971 
972         if (Status != STATUS_BUFFER_TOO_SMALL)
973         {
974             DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
975             return;
976         }
977 
978         LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
979         NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(),
980                                             HEAP_ZERO_MEMORY,
981                                             DiskEntry->LayoutBuffer,
982                                             LayoutBufferSize);
983         if (NewLayoutBuffer == NULL)
984         {
985             DPRINT1("Failed to reallocate the disk layout buffer!\n");
986             return;
987         }
988 
989         DiskEntry->LayoutBuffer = NewLayoutBuffer;
990     }
991 
992     DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
993 
994 #ifdef DUMP_PARTITION_TABLE
995     DumpPartitionTable(DiskEntry);
996 #endif
997 
998     if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
999         DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1000         DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != 0)
1001     {
1002         if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1003         {
1004             DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1005         }
1006         else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1007         {
1008             DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1009         }
1010         else
1011         {
1012             DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1013         }
1014     }
1015     else
1016     {
1017         DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1018     }
1019 
1020 
1021     if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1022     {
1023         DiskEntry->NewDisk = TRUE;
1024         DiskEntry->LayoutBuffer->PartitionCount = 4;
1025 
1026         for (i = 0; i < 4; i++)
1027             DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1028     }
1029     else
1030     {
1031         for (i = 0; i < 4; i++)
1032         {
1033             AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1034         }
1035 
1036         for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1037         {
1038             AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1039         }
1040     }
1041 
1042     ScanForUnpartitionedDiskSpace(DiskEntry);
1043 }
1044 
1045 
1046 NTSTATUS
1047 CreatePartitionList(VOID)
1048 {
1049     OBJECT_ATTRIBUTES ObjectAttributes;
1050     SYSTEM_DEVICE_INFORMATION Sdi;
1051     IO_STATUS_BLOCK Iosb;
1052     ULONG ReturnSize;
1053     NTSTATUS Status;
1054     ULONG DiskNumber;
1055     WCHAR Buffer[MAX_PATH];
1056     UNICODE_STRING Name;
1057     HANDLE FileHandle;
1058 
1059     CurrentDisk = NULL;
1060     CurrentPartition = NULL;
1061 
1062 //    BootDisk = NULL;
1063 //    BootPartition = NULL;
1064 
1065 //    TempDisk = NULL;
1066 //    TempPartition = NULL;
1067 //    FormatState = Start;
1068 
1069     InitializeListHead(&DiskListHead);
1070     InitializeListHead(&BiosDiskListHead);
1071 
1072     EnumerateBiosDiskEntries();
1073 
1074     Status = NtQuerySystemInformation(SystemDeviceInformation,
1075                                       &Sdi,
1076                                       sizeof(SYSTEM_DEVICE_INFORMATION),
1077                                       &ReturnSize);
1078     if (!NT_SUCCESS(Status))
1079     {
1080         return Status;
1081     }
1082 
1083     for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1084     {
1085         swprintf(Buffer,
1086                  L"\\Device\\Harddisk%d\\Partition0",
1087                  DiskNumber);
1088         RtlInitUnicodeString(&Name,
1089                              Buffer);
1090 
1091         InitializeObjectAttributes(&ObjectAttributes,
1092                                    &Name,
1093                                    0,
1094                                    NULL,
1095                                    NULL);
1096 
1097         Status = NtOpenFile(&FileHandle,
1098                             FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1099                             &ObjectAttributes,
1100                             &Iosb,
1101                             FILE_SHARE_READ,
1102                             FILE_SYNCHRONOUS_IO_NONALERT);
1103         if (NT_SUCCESS(Status))
1104         {
1105             AddDiskToList(FileHandle, DiskNumber);
1106 
1107             NtClose(FileHandle);
1108         }
1109     }
1110 
1111 //    UpdateDiskSignatures(List);
1112 
1113 //    AssignDriveLetters(List);
1114 
1115     return STATUS_SUCCESS;
1116 }
1117 
1118 
1119 VOID
1120 DestroyPartitionList(VOID)
1121 {
1122     PDISKENTRY DiskEntry;
1123     PBIOSDISKENTRY BiosDiskEntry;
1124     PPARTENTRY PartEntry;
1125     PLIST_ENTRY Entry;
1126 
1127     CurrentDisk = NULL;
1128     CurrentPartition = NULL;
1129 
1130     /* Release disk and partition info */
1131     while (!IsListEmpty(&DiskListHead))
1132     {
1133         Entry = RemoveHeadList(&DiskListHead);
1134         DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1135 
1136         /* Release driver name */
1137         RtlFreeUnicodeString(&DiskEntry->DriverName);
1138 
1139         /* Release primary partition list */
1140         while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1141         {
1142             Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1143             PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1144 
1145             RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry);
1146         }
1147 
1148         /* Release logical partition list */
1149         while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1150         {
1151             Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1152             PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1153 
1154             RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry);
1155         }
1156 
1157         /* Release layout buffer */
1158         if (DiskEntry->LayoutBuffer != NULL)
1159             RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->LayoutBuffer);
1160 
1161 
1162         /* Release disk entry */
1163         RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry);
1164     }
1165 
1166     /* Release the bios disk info */
1167     while (!IsListEmpty(&BiosDiskListHead))
1168     {
1169         Entry = RemoveHeadList(&BiosDiskListHead);
1170         BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1171 
1172         RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry);
1173     }
1174 }
1175 
1176 /* EOF */
1177