update for HEAD-2003091401
[reactos.git] / ntoskrnl / io / xhaldrv.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/io/xhaldrv.c
6  * PURPOSE:         Hal drive routines
7  * PROGRAMMER:      Eric Kohl (ekohl@rz-online.de)
8  *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
9  * UPDATE HISTORY:
10  *                  Created 19/06/2000
11  */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <ddk/ntddk.h>
16 #include <internal/xhal.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* LOCAL MACROS and TYPES ***************************************************/
22
23 #define  AUTO_DRIVE         ((ULONG)-1)
24
25 #define  PARTITION_MAGIC    0xaa55
26
27 #define  PARTITION_TBL_SIZE 4
28
29
30 typedef struct _PARTITION
31 {
32   unsigned char   BootFlags;                                    /* bootable?  0=no, 128=yes  */
33   unsigned char   StartingHead;                                 /* beginning head number */
34   unsigned char   StartingSector;                               /* beginning sector number */
35   unsigned char   StartingCylinder;                             /* 10 bit nmbr, with high 2 bits put in begsect */
36   unsigned char   PartitionType;                                /* Operating System type indicator code */
37   unsigned char   EndingHead;                                   /* ending head number */
38   unsigned char   EndingSector;                                 /* ending sector number */
39   unsigned char   EndingCylinder;                               /* also a 10 bit nmbr, with same high 2 bit trick */
40   unsigned int  StartingBlock;                                  /* first sector relative to start of disk */
41   unsigned int  SectorCount;                                    /* number of sectors in partition */
42 } PACKED PARTITION, *PPARTITION;
43
44
45 typedef struct _PARTITION_SECTOR
46 {
47   UCHAR BootCode[440];                          /* 0x000 */
48   ULONG Signature;                              /* 0x1B8 */
49   UCHAR Reserved[2];                            /* 0x1BC */
50   PARTITION Partition[PARTITION_TBL_SIZE];      /* 0x1BE */
51   USHORT Magic;                                 /* 0x1FE */
52 } PACKED PARTITION_SECTOR, *PPARTITION_SECTOR;
53
54
55 typedef enum _DISK_MANAGER
56 {
57   NoDiskManager,
58   OntrackDiskManager,
59   EZ_Drive
60 } DISK_MANAGER;
61
62
63 /* FUNCTIONS *****************************************************************/
64
65 NTSTATUS
66 xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName,
67                      OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo)
68 {
69   IO_STATUS_BLOCK StatusBlock;
70   DISK_GEOMETRY DiskGeometry;
71   PDEVICE_OBJECT DeviceObject = NULL;
72   PFILE_OBJECT FileObject;
73   KEVENT Event;
74   PIRP Irp;
75   NTSTATUS Status;
76
77   DPRINT("xHalpQueryDriveLayout %wZ %p\n",
78          DeviceName,
79          LayoutInfo);
80
81   /* Get the drives sector size */
82   Status = IoGetDeviceObjectPointer(DeviceName,
83                                     FILE_READ_DATA,
84                                     &FileObject,
85                                     &DeviceObject);
86   if (!NT_SUCCESS(Status))
87     {
88       DPRINT("Status %x\n",Status);
89       return(Status);
90     }
91
92   KeInitializeEvent(&Event,
93                     NotificationEvent,
94                     FALSE);
95
96   Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
97                                       DeviceObject,
98                                       NULL,
99                                       0,
100                                       &DiskGeometry,
101                                       sizeof(DISK_GEOMETRY),
102                                       FALSE,
103                                       &Event,
104                                       &StatusBlock);
105   if (Irp == NULL)
106     {
107       ObDereferenceObject(FileObject);
108       return(STATUS_INSUFFICIENT_RESOURCES);
109     }
110
111   Status = IoCallDriver(DeviceObject,
112                         Irp);
113   if (Status == STATUS_PENDING)
114     {
115       KeWaitForSingleObject(&Event,
116                             Executive,
117                             KernelMode,
118                             FALSE,
119                             NULL);
120       Status = StatusBlock.Status;
121     }
122   if (!NT_SUCCESS(Status))
123     {
124       if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
125         {
126           DiskGeometry.BytesPerSector = 512;
127         }
128       else
129         {
130           ObDereferenceObject(FileObject);
131           return(Status);
132         }
133     }
134
135   DPRINT("DiskGeometry.BytesPerSector: %d\n",
136          DiskGeometry.BytesPerSector);
137
138   /* Read the partition table */
139   Status = IoReadPartitionTable(DeviceObject,
140                                 DiskGeometry.BytesPerSector,
141                                 FALSE,
142                                 LayoutInfo);
143
144   if ((!NT_SUCCESS(Status) || (*LayoutInfo)->PartitionCount == 0) &&
145       DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
146     {
147       PDRIVE_LAYOUT_INFORMATION Buffer;
148
149       if (NT_SUCCESS(Status))
150         {
151           ExFreePool(*LayoutInfo);
152         }
153
154       /* Allocate a partition list for a single entry. */
155       Buffer = ExAllocatePool(NonPagedPool,
156                               sizeof(DRIVE_LAYOUT_INFORMATION));
157       if (Buffer != NULL)
158         {
159           RtlZeroMemory(Buffer,
160                         sizeof(DRIVE_LAYOUT_INFORMATION));
161           Buffer->PartitionCount = 1;
162           *LayoutInfo = Buffer;
163
164           Status = STATUS_SUCCESS;
165         }
166     }
167
168   ObDereferenceObject(FileObject);
169
170   return(Status);
171 }
172
173
174 static NTSTATUS
175 xHalpReadSector (IN PDEVICE_OBJECT DeviceObject,
176                  IN ULONG SectorSize,
177                  IN PLARGE_INTEGER SectorOffset,
178                  IN PVOID Sector)
179 {
180   IO_STATUS_BLOCK StatusBlock;
181   KEVENT Event;
182   PIRP Irp;
183   NTSTATUS Status;
184
185   DPRINT("xHalpReadSector() called\n");
186
187   assert(DeviceObject);
188   assert(Sector);
189
190   KeInitializeEvent(&Event,
191                     NotificationEvent,
192                     FALSE);
193
194   /* Read the sector */
195   Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
196                                      DeviceObject,
197                                      Sector,
198                                      SectorSize,
199                                      SectorOffset,
200                                      &Event,
201                                      &StatusBlock);
202
203   Status = IoCallDriver(DeviceObject,
204                         Irp);
205   if (Status == STATUS_PENDING)
206     {
207       KeWaitForSingleObject(&Event,
208                             Executive,
209                             KernelMode,
210                             FALSE,
211                             NULL);
212       Status = StatusBlock.Status;
213     }
214
215   if (!NT_SUCCESS(Status))
216     {
217       DPRINT("Reading sector failed (Status 0x%08lx)\n",
218              Status);
219       return Status;
220     }
221
222   return Status;
223 }
224
225
226 static NTSTATUS
227 xHalpWriteSector (IN PDEVICE_OBJECT DeviceObject,
228                   IN ULONG SectorSize,
229                   IN PLARGE_INTEGER SectorOffset,
230                   IN PVOID Sector)
231 {
232   IO_STATUS_BLOCK StatusBlock;
233   KEVENT Event;
234   PIRP Irp;
235   NTSTATUS Status;
236
237   DPRINT("xHalpWriteSector() called\n");
238
239   KeInitializeEvent(&Event,
240                     NotificationEvent,
241                     FALSE);
242
243   /* Write the sector */
244   Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
245                                      DeviceObject,
246                                      Sector,
247                                      SectorSize,
248                                      SectorOffset,
249                                      &Event,
250                                      &StatusBlock);
251
252   Status = IoCallDriver(DeviceObject,
253                         Irp);
254   if (Status == STATUS_PENDING)
255     {
256       KeWaitForSingleObject(&Event,
257                             Executive,
258                             KernelMode,
259                             FALSE,
260                             NULL);
261       Status = StatusBlock.Status;
262     }
263
264   if (!NT_SUCCESS(Status))
265     {
266       DPRINT("Writing sector failed (Status 0x%08lx)\n",
267              Status);
268     }
269
270   return Status;
271 }
272
273
274 VOID FASTCALL
275 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
276                IN ULONG SectorSize,
277                IN ULONG MBRTypeIdentifier,
278                OUT PVOID *Buffer)
279 {
280   LARGE_INTEGER SectorOffset;
281   PPARTITION_SECTOR Sector;
282   NTSTATUS Status;
283
284   DPRINT("xHalExamineMBR()\n");
285
286   *Buffer = NULL;
287
288   if (SectorSize < 512)
289     SectorSize = 512;
290   if (SectorSize > 4096)
291     SectorSize = 4096;
292
293   Sector = (PPARTITION_SECTOR) ExAllocatePool (PagedPool,
294                                                SectorSize);
295   if (Sector == NULL)
296     {
297       DPRINT ("Partition sector allocation failed\n");
298       return;
299     }
300
301   SectorOffset.QuadPart = 0LL;
302   Status = xHalpReadSector (DeviceObject,
303                             SectorSize,
304                             &SectorOffset,
305                             (PVOID)Sector);
306   if (!NT_SUCCESS(Status))
307     {
308       DPRINT("xHalpReadSector() failed (Status %lx)\n", Status);
309       ExFreePool(Sector);
310       return;
311     }
312
313   if (Sector->Magic != PARTITION_MAGIC)
314     {
315       DPRINT("Invalid MBR magic value\n");
316       ExFreePool(Sector);
317       return;
318     }
319
320   if (Sector->Partition[0].PartitionType != MBRTypeIdentifier)
321     {
322       DPRINT("Invalid MBRTypeIdentifier\n");
323       ExFreePool(Sector);
324       return;
325     }
326
327   if (Sector->Partition[0].PartitionType == 0x54)
328     {
329       /* Found 'Ontrack Disk Manager'. Shift all sectors by 63 */
330       DPRINT("Found 'Ontrack Disk Manager'!\n");
331       *((PULONG)Sector) = 63;
332     }
333
334   *Buffer = (PVOID)Sector;
335 }
336
337
338 static VOID
339 HalpAssignDrive(IN PUNICODE_STRING PartitionName,
340                 IN ULONG DriveNumber,
341                 IN UCHAR DriveType)
342 {
343   WCHAR DriveNameBuffer[8];
344   UNICODE_STRING DriveName;
345   ULONG i;
346
347   DPRINT("HalpAssignDrive()\n");
348
349   if ((DriveNumber != AUTO_DRIVE) && (DriveNumber < 24))
350     {
351       /* Force assignment */
352       if ((SharedUserData->DosDeviceMap & (1 << DriveNumber)) != 0)
353         {
354           DbgPrint("Drive letter already used!\n");
355           return;
356         }
357     }
358   else
359     {
360       /* Automatic assignment */
361       DriveNumber = AUTO_DRIVE;
362
363       for (i = 2; i < 24; i++)
364         {
365           if ((SharedUserData->DosDeviceMap & (1 << i)) == 0)
366             {
367               DriveNumber = i;
368               break;
369             }
370         }
371
372       if (DriveNumber == AUTO_DRIVE)
373         {
374           DbgPrint("No drive letter available!\n");
375           return;
376         }
377     }
378
379   DPRINT("DriveNumber %d\n", DriveNumber);
380
381   /* Update the shared user page */
382   SharedUserData->DosDeviceMap |= (1 << DriveNumber);
383   SharedUserData->DosDeviceDriveType[DriveNumber] = DriveType;
384
385   /* Build drive name */
386   swprintf(DriveNameBuffer,
387            L"\\??\\%C:",
388            'A' + DriveNumber);
389   RtlInitUnicodeString(&DriveName,
390                        DriveNameBuffer);
391
392   DPRINT("  %wZ ==> %wZ\n",
393          &DriveName,
394          PartitionName);
395
396   /* Create symbolic link */
397   IoCreateSymbolicLink(&DriveName,
398                        PartitionName);
399 }
400
401
402 VOID FASTCALL
403 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
404                          IN PSTRING NtDeviceName,
405                          OUT PUCHAR NtSystemPath,
406                          OUT PSTRING NtSystemPathString)
407 {
408   PDRIVE_LAYOUT_INFORMATION *LayoutArray;
409   PCONFIGURATION_INFORMATION ConfigInfo;
410   OBJECT_ATTRIBUTES ObjectAttributes;
411   IO_STATUS_BLOCK StatusBlock;
412   UNICODE_STRING UnicodeString1;
413   UNICODE_STRING UnicodeString2;
414   HANDLE FileHandle;
415   PWSTR Buffer1;
416   PWSTR Buffer2;
417   ULONG i;
418   NTSTATUS Status;
419   ULONG j;
420
421   DPRINT("xHalIoAssignDriveLetters()\n");
422
423   ConfigInfo = IoGetConfigurationInformation();
424
425   Buffer1 = (PWSTR)ExAllocatePool(PagedPool,
426                                   64 * sizeof(WCHAR));
427   Buffer2 = (PWSTR)ExAllocatePool(PagedPool,
428                                   32 * sizeof(WCHAR));
429
430   /* Create PhysicalDrive links */
431   DPRINT("Physical disk drives: %d\n", ConfigInfo->DiskCount);
432   for (i = 0; i < ConfigInfo->DiskCount; i++)
433     {
434       swprintf(Buffer1,
435                L"\\Device\\Harddisk%d\\Partition0",
436                 i);
437       RtlInitUnicodeString(&UnicodeString1,
438                            Buffer1);
439
440       InitializeObjectAttributes(&ObjectAttributes,
441                                  &UnicodeString1,
442                                  0,
443                                  NULL,
444                                  NULL);
445
446       Status = NtOpenFile(&FileHandle,
447                           0x10001,
448                           &ObjectAttributes,
449                           &StatusBlock,
450                           1,
451                           FILE_SYNCHRONOUS_IO_NONALERT);
452       if (NT_SUCCESS(Status))
453         {
454           NtClose(FileHandle);
455
456           swprintf(Buffer2,
457                    L"\\??\\PhysicalDrive%d",
458                    i);
459           RtlInitUnicodeString(&UnicodeString2,
460                                Buffer2);
461
462           DPRINT("Creating link: %S ==> %S\n",
463                  Buffer2,
464                  Buffer1);
465
466           IoCreateSymbolicLink(&UnicodeString2,
467                                &UnicodeString1);
468         }
469     }
470
471   /* Initialize layout array */
472   LayoutArray = ExAllocatePool(NonPagedPool,
473                                ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
474   RtlZeroMemory(LayoutArray,
475                 ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
476   for (i = 0; i < ConfigInfo->DiskCount; i++)
477     {
478       swprintf(Buffer1,
479                L"\\Device\\Harddisk%d\\Partition0",
480                i);
481       RtlInitUnicodeString(&UnicodeString1,
482                            Buffer1);
483
484       Status = xHalQueryDriveLayout(&UnicodeString1,
485                                     &LayoutArray[i]);
486       if (!NT_SUCCESS(Status))
487         {
488           DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n",
489                    Status);
490           LayoutArray[i] = NULL;
491           continue;
492         }
493     }
494
495 #ifndef NDEBUG
496   /* Dump layout array */
497   for (i = 0; i < ConfigInfo->DiskCount; i++)
498     {
499       DPRINT("Harddisk %d:\n",
500              i);
501
502       if (LayoutArray[i] == NULL)
503         continue;
504
505       DPRINT("Logical partitions: %d\n",
506              LayoutArray[i]->PartitionCount);
507
508       for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
509         {
510           DPRINT("  %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n",
511                  j,
512                  LayoutArray[i]->PartitionEntry[j].PartitionNumber,
513                  LayoutArray[i]->PartitionEntry[j].BootIndicator,
514                  LayoutArray[i]->PartitionEntry[j].PartitionType,
515                  LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart,
516                  LayoutArray[i]->PartitionEntry[j].PartitionLength.QuadPart);
517         }
518     }
519 #endif
520
521   /* Assign pre-assigned (registry) partitions */
522
523
524   /* Assign bootable partition on first harddisk */
525   DPRINT("Assigning bootable primary partition on first harddisk:\n");
526   if (ConfigInfo->DiskCount > 0)
527     {
528       /* Search for bootable partition */
529       for (j = 0; j < LayoutArray[0]->PartitionCount; j++)
530         {
531           if ((LayoutArray[0]->PartitionEntry[j].BootIndicator == TRUE) &&
532               IsRecognizedPartition(LayoutArray[0]->PartitionEntry[j].PartitionType))
533             {
534               swprintf(Buffer2,
535                        L"\\Device\\Harddisk0\\Partition%d",
536                        LayoutArray[0]->PartitionEntry[j].PartitionNumber);
537               RtlInitUnicodeString(&UnicodeString2,
538                                    Buffer2);
539
540               /* Assign drive */
541               DPRINT("  %wZ\n", &UnicodeString2);
542               HalpAssignDrive(&UnicodeString2,
543                               AUTO_DRIVE,
544                               DOSDEVICE_DRIVE_FIXED);
545             }
546         }
547     }
548
549   /* Assign remaining  primary partitions */
550   DPRINT("Assigning remaining primary partitions:\n");
551   for (i = 0; i < ConfigInfo->DiskCount; i++)
552     {
553       /* Search for primary partitions */
554       for (j = 0; (j < PARTITION_TBL_SIZE) && (j < LayoutArray[i]->PartitionCount); j++)
555         {
556           if ((i == 0) && (LayoutArray[i]->PartitionEntry[j].BootIndicator == TRUE))
557             continue;
558
559           if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType))
560             {
561               swprintf(Buffer2,
562                        L"\\Device\\Harddisk%d\\Partition%d",
563                        i,
564                        LayoutArray[i]->PartitionEntry[j].PartitionNumber);
565               RtlInitUnicodeString(&UnicodeString2,
566                                    Buffer2);
567
568               /* Assign drive */
569               DPRINT("  %wZ\n",
570                      &UnicodeString2);
571               HalpAssignDrive(&UnicodeString2,
572                               AUTO_DRIVE,
573                               DOSDEVICE_DRIVE_FIXED);
574             }
575         }
576     }
577
578   /* Assign extended (logical) partitions */
579   DPRINT("Assigning extended (logical) partitions:\n");
580   for (i = 0; i < ConfigInfo->DiskCount; i++)
581     {
582       if (LayoutArray[i])
583         {
584           /* Search for extended partitions */
585           for (j = PARTITION_TBL_SIZE; j < LayoutArray[i]->PartitionCount; j++)
586             {
587               if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType) &&
588                   (LayoutArray[i]->PartitionEntry[j].PartitionNumber != 0))
589                 {
590                   swprintf(Buffer2,
591                            L"\\Device\\Harddisk%d\\Partition%d",
592                            i,
593                            LayoutArray[i]->PartitionEntry[j].PartitionNumber);
594                   RtlInitUnicodeString(&UnicodeString2,
595                                        Buffer2);
596
597                   /* Assign drive */
598                   DPRINT("  %wZ\n",
599                          &UnicodeString2);
600                   HalpAssignDrive(&UnicodeString2,
601                                   AUTO_DRIVE,
602                                   DOSDEVICE_DRIVE_FIXED);
603                 }
604             }
605         }
606     }
607
608   /* Assign removable disk drives */
609   DPRINT("Assigning removable disk drives:\n");
610   for (i = 0; i < ConfigInfo->DiskCount; i++)
611     {
612       /* Search for virtual partitions */
613       if (LayoutArray[i]->PartitionCount == 1 &&
614           LayoutArray[i]->PartitionEntry[0].PartitionType == 0)
615         {
616           swprintf(Buffer2,
617                    L"\\Device\\Harddisk%d\\Partition1",
618                    i);
619           RtlInitUnicodeString(&UnicodeString2,
620                                Buffer2);
621
622           /* Assign drive */
623           DPRINT("  %wZ\n",
624                  &UnicodeString2);
625           HalpAssignDrive(&UnicodeString2,
626                           AUTO_DRIVE,
627                           DOSDEVICE_DRIVE_REMOVABLE);
628         }
629     }
630
631   /* Free layout array */
632   for (i = 0; i < ConfigInfo->DiskCount; i++)
633     {
634       if (LayoutArray[i] != NULL)
635         ExFreePool(LayoutArray[i]);
636     }
637   ExFreePool(LayoutArray);
638
639   /* Assign floppy drives */
640   DPRINT("Floppy drives: %d\n", ConfigInfo->FloppyCount);
641   for (i = 0; i < ConfigInfo->FloppyCount; i++)
642     {
643       swprintf(Buffer1,
644                L"\\Device\\Floppy%d",
645                i);
646       RtlInitUnicodeString(&UnicodeString1,
647                            Buffer1);
648
649       /* Assign drive letters A: or B: or first free drive letter */
650       DPRINT("  %wZ\n",
651              &UnicodeString1);
652       HalpAssignDrive(&UnicodeString1,
653                       (i < 2) ? i : AUTO_DRIVE,
654                       DOSDEVICE_DRIVE_REMOVABLE);
655     }
656
657   /* Assign cdrom drives */
658   DPRINT("CD-Rom drives: %d\n", ConfigInfo->CdRomCount);
659   for (i = 0; i < ConfigInfo->CdRomCount; i++)
660     {
661       swprintf(Buffer1,
662                L"\\Device\\CdRom%d",
663                i);
664       RtlInitUnicodeString(&UnicodeString1,
665                            Buffer1);
666
667       /* Assign first free drive letter */
668       DPRINT("  %wZ\n", &UnicodeString1);
669       HalpAssignDrive(&UnicodeString1,
670                       AUTO_DRIVE,
671                       DOSDEVICE_DRIVE_CDROM);
672     }
673
674   /* Anything else to do? */
675
676   ExFreePool(Buffer2);
677   ExFreePool(Buffer1);
678 }
679
680
681 NTSTATUS FASTCALL
682 xHalIoReadPartitionTable(PDEVICE_OBJECT DeviceObject,
683                          ULONG SectorSize,
684                          BOOLEAN ReturnRecognizedPartitions,
685                          PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
686 {
687   LARGE_INTEGER RealPartitionOffset;
688   ULONGLONG PartitionOffset;
689   ULONGLONG nextPartitionOffset;
690   ULONGLONG containerOffset;
691   NTSTATUS Status;
692   PPARTITION_SECTOR PartitionSector;
693   PDRIVE_LAYOUT_INFORMATION LayoutBuffer;
694   ULONG i;
695   ULONG Count = 0;
696   ULONG Number = 1;
697   BOOLEAN ExtendedFound = FALSE;
698   PVOID MbrBuffer;
699   DISK_MANAGER DiskManager = NoDiskManager;
700
701   DPRINT("xHalIoReadPartitionTable(%p %lu %x %p)\n",
702          DeviceObject,
703          SectorSize,
704          ReturnRecognizedPartitions,
705          PartitionBuffer);
706
707   *PartitionBuffer = NULL;
708
709   /* Check sector size */
710   if (SectorSize < 512)
711     SectorSize = 512;
712   if (SectorSize > 4096)
713     SectorSize = 4096;
714
715   /* Check for 'Ontrack Disk Manager' */
716   xHalExamineMBR(DeviceObject,
717                  SectorSize,
718                  0x54,
719                  &MbrBuffer);
720   if (MbrBuffer != NULL)
721     {
722       DPRINT("Found 'Ontrack Disk Manager'\n");
723       DiskManager = OntrackDiskManager;
724       ExFreePool(MbrBuffer);
725     }
726
727   /* Check for 'EZ-Drive' */
728   xHalExamineMBR(DeviceObject,
729                  SectorSize,
730                  0x55,
731                  &MbrBuffer);
732   if (MbrBuffer != NULL)
733     {
734       DPRINT("Found 'EZ-Drive'\n");
735       DiskManager = EZ_Drive;
736       ExFreePool(MbrBuffer);
737     }
738
739   PartitionSector = (PPARTITION_SECTOR)ExAllocatePool(PagedPool,
740                                                       SectorSize);
741   if (PartitionSector == NULL)
742     {
743       return(STATUS_INSUFFICIENT_RESOURCES);
744     }
745
746   LayoutBuffer = (PDRIVE_LAYOUT_INFORMATION)ExAllocatePool(NonPagedPool,
747                                                            0x1000);
748   if (LayoutBuffer == NULL)
749     {
750       ExFreePool(PartitionSector);
751       return(STATUS_INSUFFICIENT_RESOURCES);
752     }
753
754   RtlZeroMemory(LayoutBuffer,
755                 0x1000);
756
757   PartitionOffset = 0ULL;
758   containerOffset = 0ULL;
759
760   do
761     {
762       DPRINT("PartitionOffset: %I64u\n", PartitionOffset / SectorSize);
763
764       /* Handle disk managers */
765       if (DiskManager == OntrackDiskManager)
766         {
767           /* Shift offset by 63 sectors */
768           RealPartitionOffset.QuadPart = PartitionOffset + (ULONGLONG)(63 * SectorSize);
769         }
770       else if (DiskManager == EZ_Drive && PartitionOffset == 0ULL)
771         {
772           /* Use sector 1 instead of sector 0 */
773           RealPartitionOffset.QuadPart = (ULONGLONG)SectorSize;
774         }
775       else
776         {
777           RealPartitionOffset.QuadPart = PartitionOffset;
778         }
779
780       DPRINT ("RealPartitionOffset: %I64u\n",
781               RealPartitionOffset.QuadPart / SectorSize);
782
783       Status = xHalpReadSector (DeviceObject,
784                                 SectorSize,
785                                 &RealPartitionOffset,
786                                 PartitionSector);
787       if (!NT_SUCCESS(Status))
788         {
789           DPRINT ("Failed to read partition table sector (Status = 0x%08lx)\n",
790                   Status);
791           ExFreePool (PartitionSector);
792           ExFreePool (LayoutBuffer);
793           return Status;
794         }
795
796       /* Check the boot sector id */
797       DPRINT("Magic %x\n", PartitionSector->Magic);
798       if (PartitionSector->Magic != PARTITION_MAGIC)
799         {
800           DPRINT ("Invalid partition sector magic\n");
801           ExFreePool (PartitionSector);
802           *PartitionBuffer = LayoutBuffer;
803           return STATUS_SUCCESS;
804         }
805
806 #ifndef NDEBUG
807       for (i = 0; i < PARTITION_TBL_SIZE; i++)
808         {
809           DPRINT1("  %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
810                   i,
811                   PartitionSector->Partition[i].BootFlags,
812                   PartitionSector->Partition[i].PartitionType,
813                   PartitionSector->Partition[i].StartingHead,
814                   PartitionSector->Partition[i].StartingSector & 0x3f,
815                   (((PartitionSector->Partition[i].StartingSector) & 0xc0) << 2) +
816                      PartitionSector->Partition[i].StartingCylinder,
817                   PartitionSector->Partition[i].EndingHead,
818                   PartitionSector->Partition[i].EndingSector & 0x3f,
819                   (((PartitionSector->Partition[i].EndingSector) & 0xc0) << 2) +
820                      PartitionSector->Partition[i].EndingCylinder,
821                   PartitionSector->Partition[i].StartingBlock,
822                   PartitionSector->Partition[i].SectorCount);
823         }
824 #endif
825
826       if (PartitionOffset == 0ULL)
827         {
828           LayoutBuffer->Signature = PartitionSector->Signature;
829           DPRINT("Disk signature: %lx\n", LayoutBuffer->Signature);
830         }
831
832       ExtendedFound = FALSE;
833
834       for (i = 0; i < PARTITION_TBL_SIZE; i++)
835         {
836           if (IsContainerPartition(PartitionSector->Partition[i].PartitionType))
837             {
838               ExtendedFound = TRUE;
839               if ((ULONGLONG) containerOffset == (ULONGLONG) 0)
840                 {
841                   containerOffset = PartitionOffset;
842                 }
843               nextPartitionOffset = (ULONGLONG) containerOffset +
844                 (ULONGLONG) PartitionSector->Partition[i].StartingBlock *
845                 (ULONGLONG) SectorSize;
846             }
847
848           if ((ReturnRecognizedPartitions == FALSE) ||
849                ((ReturnRecognizedPartitions == TRUE) &&
850                 IsRecognizedPartition(PartitionSector->Partition[i].PartitionType)))
851             {
852               /* handle normal partition */
853               DPRINT("Partition %u: Normal Partition\n", i);
854               Count = LayoutBuffer->PartitionCount;
855               DPRINT("Logical Partition %u\n", Count);
856
857               if (PartitionSector->Partition[i].StartingBlock == 0)
858                 {
859                   LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart = 0;
860                 }
861               else if (IsContainerPartition(PartitionSector->Partition[i].PartitionType))
862                 {
863                   LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart =
864                     (ULONGLONG) containerOffset +
865                     (ULONGLONG) PartitionSector->Partition[i].StartingBlock *
866                     (ULONGLONG) SectorSize;
867                 }
868               else
869                 {
870                   LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart =
871                     (ULONGLONG)PartitionOffset +
872                     ((ULONGLONG)PartitionSector->Partition[i].StartingBlock * (ULONGLONG)SectorSize);
873                 }
874               LayoutBuffer->PartitionEntry[Count].PartitionLength.QuadPart =
875                 (ULONGLONG)PartitionSector->Partition[i].SectorCount * (ULONGLONG)SectorSize;
876               LayoutBuffer->PartitionEntry[Count].HiddenSectors =
877                 PartitionSector->Partition[i].StartingBlock;
878
879               if (IsRecognizedPartition(PartitionSector->Partition[i].PartitionType))
880                 {
881                   LayoutBuffer->PartitionEntry[Count].PartitionNumber = Number;
882                   Number++;
883                 }
884               else
885                 {
886                   LayoutBuffer->PartitionEntry[Count].PartitionNumber = 0;
887                 }
888
889               LayoutBuffer->PartitionEntry[Count].PartitionType =
890                 PartitionSector->Partition[i].PartitionType;
891               LayoutBuffer->PartitionEntry[Count].BootIndicator =
892                 (PartitionSector->Partition[i].BootFlags & 0x80)?TRUE:FALSE;
893               LayoutBuffer->PartitionEntry[Count].RecognizedPartition =
894                 IsRecognizedPartition (PartitionSector->Partition[i].PartitionType);
895               LayoutBuffer->PartitionEntry[Count].RewritePartition = FALSE;
896
897               DPRINT(" %ld: nr: %d boot: %1x type: %x start: 0x%I64x count: 0x%I64x\n",
898                      Count,
899                      LayoutBuffer->PartitionEntry[Count].PartitionNumber,
900                      LayoutBuffer->PartitionEntry[Count].BootIndicator,
901                      LayoutBuffer->PartitionEntry[Count].PartitionType,
902                      LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart,
903                      LayoutBuffer->PartitionEntry[Count].PartitionLength.QuadPart);
904
905               LayoutBuffer->PartitionCount++;
906             }
907         }
908
909       PartitionOffset = nextPartitionOffset;
910     }
911   while (ExtendedFound == TRUE);
912
913   *PartitionBuffer = LayoutBuffer;
914   ExFreePool(PartitionSector);
915
916   return(STATUS_SUCCESS);
917 }
918
919
920 NTSTATUS FASTCALL
921 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
922                               IN ULONG SectorSize,
923                               IN ULONG PartitionNumber,
924                               IN ULONG PartitionType)
925 {
926   PPARTITION_SECTOR PartitionSector;
927   LARGE_INTEGER RealPartitionOffset;
928   ULONGLONG PartitionOffset;
929   ULONGLONG nextPartitionOffset;
930   ULONGLONG containerOffset;
931   NTSTATUS Status;
932   ULONG i;
933   ULONG Number = 1;
934   BOOLEAN ExtendedFound = FALSE;
935   DISK_MANAGER DiskManager = NoDiskManager;
936
937   DPRINT ("xHalIoSetPartitionInformation(%p %lu %lu %lu)\n",
938           DeviceObject,
939           SectorSize,
940           PartitionNumber,
941           PartitionType);
942
943   /* Check sector size */
944   if (SectorSize < 512)
945     SectorSize = 512;
946   if (SectorSize > 4096)
947     SectorSize = 4096;
948
949   /* Check for 'Ontrack Disk Manager' */
950   xHalExamineMBR (DeviceObject,
951                   SectorSize,
952                   0x54,
953                   (PVOID*) &PartitionSector);
954   if (PartitionSector != NULL)
955     {
956       DPRINT ("Found 'Ontrack Disk Manager'\n");
957       DiskManager = OntrackDiskManager;
958       ExFreePool (PartitionSector);
959     }
960
961   /* Check for 'EZ-Drive' */
962   xHalExamineMBR (DeviceObject,
963                   SectorSize,
964                   0x55,
965                   (PVOID*) &PartitionSector);
966   if (PartitionSector != NULL)
967     {
968       DPRINT ("Found 'EZ-Drive'\n");
969       DiskManager = EZ_Drive;
970       ExFreePool (PartitionSector);
971     }
972
973   /* Allocate partition sector */
974   PartitionSector = (PPARTITION_SECTOR) ExAllocatePool (PagedPool,
975                                                         SectorSize);
976   if (PartitionSector == NULL)
977     {
978       return STATUS_INSUFFICIENT_RESOURCES;
979     }
980
981   PartitionOffset = 0ULL;
982   containerOffset = 0ULL;
983
984   do
985     {
986       DPRINT ("PartitionOffset: %I64u\n", PartitionOffset / SectorSize);
987
988       /* Handle disk managers */
989       if (DiskManager == OntrackDiskManager)
990         {
991           /* Shift offset by 63 sectors */
992           RealPartitionOffset.QuadPart = PartitionOffset + (ULONGLONG)(63 * SectorSize);
993         }
994       else if (DiskManager == EZ_Drive && PartitionOffset == 0ULL)
995         {
996           /* Use sector 1 instead of sector 0 */
997           RealPartitionOffset.QuadPart = (ULONGLONG)SectorSize;
998         }
999       else
1000         {
1001           RealPartitionOffset.QuadPart = PartitionOffset;
1002         }
1003
1004       DPRINT ("RealPartitionOffset: %I64u\n",
1005               RealPartitionOffset.QuadPart / SectorSize);
1006
1007       Status = xHalpReadSector (DeviceObject,
1008                                 SectorSize,
1009                                 &RealPartitionOffset,
1010                                 PartitionSector);
1011       if (!NT_SUCCESS (Status))
1012         {
1013           DPRINT ("Failed to read partition table sector (Status = 0x%08lx)\n",
1014                   Status);
1015           ExFreePool (PartitionSector);
1016           return Status;
1017         }
1018
1019       /* Check the boot sector id */
1020       DPRINT("Magic %x\n", PartitionSector->Magic);
1021       if (PartitionSector->Magic != PARTITION_MAGIC)
1022         {
1023           DPRINT ("Invalid partition sector magic\n");
1024           ExFreePool (PartitionSector);
1025           return STATUS_UNSUCCESSFUL;
1026         }
1027
1028 #ifndef NDEBUG
1029       for (i = 0; i < PARTITION_TBL_SIZE; i++)
1030         {
1031           DPRINT1("  %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
1032                   i,
1033                   PartitionSector->Partition[i].BootFlags,
1034                   PartitionSector->Partition[i].PartitionType,
1035                   PartitionSector->Partition[i].StartingHead,
1036                   PartitionSector->Partition[i].StartingSector & 0x3f,
1037                   (((PartitionSector->Partition[i].StartingSector) & 0xc0) << 2) +
1038                      PartitionSector->Partition[i].StartingCylinder,
1039                   PartitionSector->Partition[i].EndingHead,
1040                   PartitionSector->Partition[i].EndingSector & 0x3f,
1041                   (((PartitionSector->Partition[i].EndingSector) & 0xc0) << 2) +
1042                      PartitionSector->Partition[i].EndingCylinder,
1043                   PartitionSector->Partition[i].StartingBlock,
1044                   PartitionSector->Partition[i].SectorCount);
1045         }
1046 #endif
1047
1048       ExtendedFound = FALSE;
1049       for (i = 0; i < PARTITION_TBL_SIZE; i++)
1050         {
1051           if (IsContainerPartition (PartitionSector->Partition[i].PartitionType))
1052             {
1053               ExtendedFound = TRUE;
1054               if (containerOffset == 0ULL)
1055                 {
1056                   containerOffset = PartitionOffset;
1057                 }
1058               nextPartitionOffset = containerOffset +
1059                 (ULONGLONG) PartitionSector->Partition[i].StartingBlock *
1060                 (ULONGLONG) SectorSize;
1061             }
1062
1063           /* Handle recognized partition */
1064           if (IsRecognizedPartition (PartitionSector->Partition[i].PartitionType))
1065             {
1066               if (Number == PartitionNumber)
1067                 {
1068                   /* Set partition type */
1069                   PartitionSector->Partition[i].PartitionType = PartitionType;
1070
1071                   /* Write partition sector */
1072                   Status = xHalpWriteSector (DeviceObject,
1073                                              SectorSize,
1074                                              &RealPartitionOffset,
1075                                              PartitionSector);
1076                   if (!NT_SUCCESS(Status))
1077                     {
1078                       DPRINT1("xHalpWriteSector() failed (Status %lx)\n", Status);
1079                     }
1080
1081                   ExFreePool (PartitionSector);
1082                   return Status;
1083                 }
1084               Number++;
1085             }
1086         }
1087
1088       PartitionOffset = nextPartitionOffset;
1089     }
1090   while (ExtendedFound == TRUE);
1091
1092   ExFreePool(PartitionSector);
1093
1094   return STATUS_UNSUCCESSFUL;
1095 }
1096
1097
1098 NTSTATUS FASTCALL
1099 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
1100                           IN ULONG SectorSize,
1101                           IN ULONG SectorsPerTrack,
1102                           IN ULONG NumberOfHeads,
1103                           IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
1104 {
1105   PPARTITION_SECTOR PartitionSector;
1106   LARGE_INTEGER RealPartitionOffset;
1107   ULONGLONG PartitionOffset;
1108   ULONGLONG NextPartitionOffset;
1109   ULONGLONG ContainerOffset;
1110   BOOLEAN ContainerEntry;
1111   DISK_MANAGER DiskManager;
1112   ULONG i;
1113   ULONG j;
1114   ULONG StartBlock;
1115   ULONG SectorCount;
1116   ULONG StartCylinder;
1117   ULONG StartSector;
1118   ULONG StartHead;
1119   ULONG EndCylinder;
1120   ULONG EndSector;
1121   ULONG EndHead;
1122   ULONG lba;
1123   ULONG x;
1124   NTSTATUS Status;
1125
1126   DPRINT ("xHalIoWritePartitionTable(%p %lu %lu %lu %p)\n",
1127           DeviceObject,
1128           SectorSize,
1129           SectorsPerTrack,
1130           NumberOfHeads,
1131           PartitionBuffer);
1132
1133   assert(DeviceObject);
1134   assert(PartitionBuffer);
1135
1136   DiskManager = NoDiskManager;
1137
1138   /* Check sector size */
1139   if (SectorSize < 512)
1140     SectorSize = 512;
1141   if (SectorSize > 4096)
1142     SectorSize = 4096;
1143
1144   /* Check for 'Ontrack Disk Manager' */
1145   xHalExamineMBR (DeviceObject,
1146                   SectorSize,
1147                   0x54,
1148                   (PVOID *) &PartitionSector);
1149   if (PartitionSector != NULL)
1150     {
1151       DPRINT ("Found 'Ontrack Disk Manager'\n");
1152       DiskManager = OntrackDiskManager;
1153       ExFreePool (PartitionSector);
1154     }
1155
1156   /* Check for 'EZ-Drive' */
1157   xHalExamineMBR (DeviceObject,
1158                   SectorSize,
1159                   0x55,
1160                   (PVOID *) &PartitionSector);
1161   if (PartitionSector != NULL)
1162     {
1163       DPRINT ("Found 'EZ-Drive'\n");
1164       DiskManager = EZ_Drive;
1165       ExFreePool (PartitionSector);
1166     }
1167
1168   /* Allocate partition sector */
1169   PartitionSector = (PPARTITION_SECTOR)ExAllocatePool(PagedPool,
1170                                                       SectorSize);
1171   if (PartitionSector == NULL)
1172     {
1173       return STATUS_INSUFFICIENT_RESOURCES;
1174     }
1175
1176   Status = STATUS_SUCCESS;
1177   PartitionOffset = 0ULL;
1178   ContainerOffset = 0ULL;
1179   for (i = 0; i < PartitionBuffer->PartitionCount; i += 4)
1180     {
1181       DPRINT ("PartitionOffset: %I64u\n", PartitionOffset);
1182       DPRINT ("ContainerOffset: %I64u\n", ContainerOffset);
1183
1184       /* Handle disk managers */
1185       if (DiskManager == OntrackDiskManager)
1186         {
1187           /* Shift offset by 63 sectors */
1188           RealPartitionOffset.QuadPart = PartitionOffset + (ULONGLONG)(63 * SectorSize);
1189         }
1190       else if (DiskManager == EZ_Drive && PartitionOffset == 0ULL)
1191         {
1192           /* Use sector 1 instead of sector 0 */
1193           RealPartitionOffset.QuadPart = (ULONGLONG)SectorSize;
1194         }
1195       else
1196         {
1197           RealPartitionOffset.QuadPart = PartitionOffset;
1198         }
1199
1200       /* Write modified partition tables */
1201       if (PartitionBuffer->PartitionEntry[i].RewritePartition == TRUE ||
1202           PartitionBuffer->PartitionEntry[i + 1].RewritePartition == TRUE ||
1203           PartitionBuffer->PartitionEntry[i + 2].RewritePartition == TRUE ||
1204           PartitionBuffer->PartitionEntry[i + 3].RewritePartition == TRUE)
1205         {
1206           /* Read partition sector */
1207           Status = xHalpReadSector (DeviceObject,
1208                                     SectorSize,
1209                                     &RealPartitionOffset,
1210                                     PartitionSector);
1211           if (!NT_SUCCESS(Status))
1212             {
1213               DPRINT1 ("xHalpReadSector() failed (Status %lx)\n", Status);
1214               break;
1215             }
1216
1217           /* Initialize a new partition sector */
1218           if (PartitionSector->Magic != PARTITION_MAGIC)
1219             {
1220               /* Create empty partition sector */
1221               RtlZeroMemory (PartitionSector,
1222                              SectorSize);
1223               PartitionSector->Magic = PARTITION_MAGIC;
1224             }
1225
1226           /* Update partition sector entries */
1227           for (j = 0; j < 4; j++)
1228             {
1229               if (PartitionBuffer->PartitionEntry[i + j].RewritePartition == TRUE)
1230                 {
1231                   /* Set partition boot flag */
1232                   if (PartitionBuffer->PartitionEntry[i + j].BootIndicator)
1233                     {
1234                       PartitionSector->Partition[j].BootFlags |= 0x80;
1235                     }
1236                   else
1237                     {
1238                       PartitionSector->Partition[j].BootFlags &= ~0x80;
1239                     }
1240
1241                   /* Set partition type */
1242                   PartitionSector->Partition[j].PartitionType =
1243                     PartitionBuffer->PartitionEntry[i + j].PartitionType;
1244
1245                   /* Set partition data */
1246                   if (PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart == 0ULL &&
1247                       PartitionBuffer->PartitionEntry[i + j].PartitionLength.QuadPart == 0ULL)
1248                     {
1249                       PartitionSector->Partition[j].StartingBlock = 0;
1250                       PartitionSector->Partition[j].SectorCount = 0;
1251                       PartitionSector->Partition[j].StartingCylinder = 0;
1252                       PartitionSector->Partition[j].StartingHead = 0;
1253                       PartitionSector->Partition[j].StartingSector = 0;
1254                       PartitionSector->Partition[j].EndingCylinder = 0;
1255                       PartitionSector->Partition[j].EndingHead = 0;
1256                       PartitionSector->Partition[j].EndingSector = 0;
1257                     }
1258                   else
1259                     {
1260                       /*
1261                        * CHS formulas:
1262                        * x = LBA DIV SectorsPerTrack
1263                        * cylinder = (x DIV NumberOfHeads) % 1024
1264                        * head = x MOD NumberOfHeads
1265                        * sector = (LBA MOD SectorsPerTrack) + 1
1266                        */
1267
1268                       /* Compute starting CHS values */
1269                       lba = (PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart) / SectorSize;
1270                       x = lba / SectorsPerTrack;
1271                       StartCylinder = (x / NumberOfHeads) %1024;
1272                       StartHead = x % NumberOfHeads;
1273                       StartSector = (lba % SectorsPerTrack) + 1;
1274                       DPRINT ("StartingOffset (LBA:%d  C:%d  H:%d  S:%d)\n",
1275                               lba, StartCylinder, StartHead, StartSector);
1276
1277                       /* Compute ending CHS values */
1278                       lba = (PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart +
1279                              (PartitionBuffer->PartitionEntry[i + j].PartitionLength.QuadPart - 1)) / SectorSize;
1280                       x = lba / SectorsPerTrack;
1281                       EndCylinder = (x / NumberOfHeads) % 1024;
1282                       EndHead = x % NumberOfHeads;
1283                       EndSector = (lba % SectorsPerTrack) + 1;
1284                       DPRINT ("EndingOffset (LBA:%d  C:%d  H:%d  S:%d)\n",
1285                               lba, EndCylinder, EndHead, EndSector);
1286
1287                       /* Set starting CHS values */
1288                       PartitionSector->Partition[j].StartingCylinder = StartCylinder & 0xff;
1289                       PartitionSector->Partition[j].StartingHead = StartHead;
1290                       PartitionSector->Partition[j].StartingSector =
1291                         ((StartCylinder & 0x0300) >> 2) + (StartSector & 0x3f);
1292
1293                       /* Set ending CHS values */
1294                       PartitionSector->Partition[j].EndingCylinder = EndCylinder & 0xff;
1295                       PartitionSector->Partition[j].EndingHead = EndHead;
1296                       PartitionSector->Partition[j].EndingSector = 
1297                         ((EndCylinder & 0x0300) >> 2) + (EndSector & 0x3f);
1298
1299                       /* Calculate start sector and sector count */
1300                       StartBlock =
1301                         (PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart - ContainerOffset) / SectorSize;
1302                       SectorCount =
1303                         PartitionBuffer->PartitionEntry[i + j].PartitionLength.QuadPart / SectorSize;
1304                       DPRINT ("LBA (StartBlock:%lu  SectorCount:%lu)\n",
1305                               StartBlock, SectorCount);
1306
1307                       /* Set start sector and sector count */
1308                       PartitionSector->Partition[j].StartingBlock = StartBlock;
1309                       PartitionSector->Partition[j].SectorCount = SectorCount;
1310                     }
1311                 }
1312             }
1313
1314           /* Write partition sector */
1315           Status = xHalpWriteSector (DeviceObject,
1316                                      SectorSize,
1317                                      &RealPartitionOffset,
1318                                      PartitionSector);
1319           if (!NT_SUCCESS(Status))
1320             {
1321               DPRINT1("xHalpWriteSector() failed (Status %lx)\n", Status);
1322               break;
1323             }
1324         }
1325
1326       ContainerEntry = FALSE;
1327       for (j = 0; j < 4; j++)
1328         {
1329           if (IsContainerPartition (PartitionBuffer->PartitionEntry[i + j].PartitionType))
1330             {
1331               ContainerEntry = TRUE;
1332               NextPartitionOffset = 
1333                 PartitionBuffer->PartitionEntry[i + j].StartingOffset.QuadPart;
1334
1335               if (ContainerOffset == 0ULL)
1336                 {
1337                   ContainerOffset = NextPartitionOffset;
1338                 }
1339             }
1340         }
1341
1342       if (ContainerEntry == FALSE)
1343         {
1344           DPRINT ("No container entry in partition sector!\n");
1345           break;
1346         }
1347
1348       PartitionOffset = NextPartitionOffset;
1349     }
1350
1351   ExFreePool (PartitionSector);
1352
1353   return Status;
1354 }
1355
1356 /* EOF */