update for HEAD-2003050101
[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  * UPDATE HISTORY:
9  *                  Created 19/06/2000
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/xhal.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* LOCAL MACROS and TYPES ***************************************************/
21
22 #define  AUTO_DRIVE         ((ULONG)-1)
23
24 #define  PARTITION_MAGIC    0xaa55
25
26 #define  PARTITION_TBL_SIZE 4
27
28
29 typedef struct _PARTITION
30 {
31   unsigned char   BootFlags;                                    /* bootable?  0=no, 128=yes  */
32   unsigned char   StartingHead;                                 /* beginning head number */
33   unsigned char   StartingSector;                               /* beginning sector number */
34   unsigned char   StartingCylinder;                             /* 10 bit nmbr, with high 2 bits put in begsect */
35   unsigned char   PartitionType;                                /* Operating System type indicator code */
36   unsigned char   EndingHead;                                   /* ending head number */
37   unsigned char   EndingSector;                                 /* ending sector number */
38   unsigned char   EndingCylinder;                               /* also a 10 bit nmbr, with same high 2 bit trick */
39   unsigned int  StartingBlock;                                  /* first sector relative to start of disk */
40   unsigned int  SectorCount;                                    /* number of sectors in partition */
41 } PACKED PARTITION, *PPARTITION;
42
43
44 typedef struct _PARTITION_SECTOR
45 {
46   UCHAR BootCode[440];                          /* 0x000 */
47   ULONG Signature;                              /* 0x1B8 */
48   UCHAR Reserved[2];                            /* 0x1BC */
49   PARTITION Partition[PARTITION_TBL_SIZE];      /* 0x1BE */
50   USHORT Magic;                                 /* 0x1FE */
51 } PACKED PARTITION_SECTOR, *PPARTITION_SECTOR;
52
53
54 typedef enum _DISK_MANAGER
55 {
56   NoDiskManager,
57   OntrackDiskManager,
58   EZ_Drive
59 } DISK_MANAGER;
60
61
62 /* FUNCTIONS *****************************************************************/
63
64 NTSTATUS
65 xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName,
66                      OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo)
67 {
68   IO_STATUS_BLOCK StatusBlock;
69   DISK_GEOMETRY DiskGeometry;
70   PDEVICE_OBJECT DeviceObject = NULL;
71   PFILE_OBJECT FileObject;
72   KEVENT Event;
73   PIRP Irp;
74   NTSTATUS Status;
75
76   DPRINT("xHalpQueryDriveLayout %wZ %p\n",
77          DeviceName,
78          LayoutInfo);
79
80   /* Get the drives sector size */
81   Status = IoGetDeviceObjectPointer(DeviceName,
82                                     FILE_READ_DATA,
83                                     &FileObject,
84                                     &DeviceObject);
85   if (!NT_SUCCESS(Status))
86     {
87       DPRINT("Status %x\n",Status);
88       return(Status);
89     }
90
91   KeInitializeEvent(&Event,
92                     NotificationEvent,
93                     FALSE);
94
95   Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
96                                       DeviceObject,
97                                       NULL,
98                                       0,
99                                       &DiskGeometry,
100                                       sizeof(DISK_GEOMETRY),
101                                       FALSE,
102                                       &Event,
103                                       &StatusBlock);
104   if (Irp == NULL)
105     {
106       ObDereferenceObject(FileObject);
107       return(STATUS_INSUFFICIENT_RESOURCES);
108     }
109
110   Status = IoCallDriver(DeviceObject,
111                         Irp);
112   if (Status == STATUS_PENDING)
113     {
114       KeWaitForSingleObject(&Event,
115                             Executive,
116                             KernelMode,
117                             FALSE,
118                             NULL);
119       Status = StatusBlock.Status;
120     }
121   if (!NT_SUCCESS(Status))
122     {
123       if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
124         {
125           DiskGeometry.BytesPerSector = 512;
126         }
127       else
128         {
129           ObDereferenceObject(FileObject);
130           return(Status);
131         }
132     }
133
134   DPRINT("DiskGeometry.BytesPerSector: %d\n",
135          DiskGeometry.BytesPerSector);
136
137   /* read the partition table */
138   Status = IoReadPartitionTable(DeviceObject,
139                                 DiskGeometry.BytesPerSector,
140                                 FALSE,
141                                 LayoutInfo);
142
143   if ((!NT_SUCCESS(Status) || (*LayoutInfo)->PartitionCount == 0) &&
144       DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
145     {
146       PDRIVE_LAYOUT_INFORMATION Buffer;
147
148       if (NT_SUCCESS(Status))
149         {
150           ExFreePool(*LayoutInfo);
151         }
152
153       /* Allocate a partition list for a single entry. */
154       Buffer = ExAllocatePool(NonPagedPool,
155                               sizeof(DRIVE_LAYOUT_INFORMATION));
156       if (Buffer != NULL)
157         {
158           RtlZeroMemory(Buffer,
159                         sizeof(DRIVE_LAYOUT_INFORMATION));
160           Buffer->PartitionCount = 1;
161           *LayoutInfo = Buffer;
162
163           Status = STATUS_SUCCESS;
164         }
165     }
166
167   ObDereferenceObject(FileObject);
168
169   return(Status);
170 }
171
172
173 static NTSTATUS
174 xHalpReadSector(IN PDEVICE_OBJECT DeviceObject,
175                 IN ULONG SectorSize,
176                 IN PLARGE_INTEGER SectorOffset,
177                 OUT PVOID *Buffer)
178 {
179   KEVENT Event;
180   IO_STATUS_BLOCK StatusBlock;
181   PUCHAR Sector;
182   PIRP Irp;
183   NTSTATUS Status;
184
185   DPRINT("xHalReadMBR()\n");
186
187   assert(DeviceObject);
188   assert(Buffer);
189
190   *Buffer = NULL;
191
192   if (SectorSize < 512)
193     SectorSize = 512;
194   if (SectorSize > 4096)
195     SectorSize = 4096;
196
197   Sector = (PUCHAR)ExAllocatePool(PagedPool,
198                                   SectorSize);
199   if (Sector == NULL)
200     return STATUS_NO_MEMORY;
201
202   KeInitializeEvent(&Event,
203                     NotificationEvent,
204                     FALSE);
205
206   /* Read MBR (Master Boot Record) */
207   Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
208                                      DeviceObject,
209                                      Sector,
210                                      SectorSize,
211                                      SectorOffset,
212                                      &Event,
213                                      &StatusBlock);
214
215   Status = IoCallDriver(DeviceObject,
216                         Irp);
217   if (Status == STATUS_PENDING)
218     {
219       KeWaitForSingleObject(&Event,
220                             Executive,
221                             KernelMode,
222                             FALSE,
223                             NULL);
224       Status = StatusBlock.Status;
225     }
226
227   if (!NT_SUCCESS(Status))
228     {
229       DPRINT("Reading MBR failed (Status 0x%08lx)\n",
230              Status);
231       ExFreePool(Sector);
232       return Status;
233     }
234
235   *Buffer = (PVOID)Sector;
236   return Status;
237 }
238
239
240 static NTSTATUS
241 xHalpWriteSector(IN PDEVICE_OBJECT DeviceObject,
242                  IN ULONG SectorSize,
243                  IN PLARGE_INTEGER SectorOffset,
244                  OUT PVOID Sector)
245 {
246   KEVENT Event;
247   IO_STATUS_BLOCK StatusBlock;
248   PIRP Irp;
249   NTSTATUS Status;
250
251   DPRINT("xHalWriteMBR()\n");
252
253   if (SectorSize < 512)
254     SectorSize = 512;
255   if (SectorSize > 4096)
256     SectorSize = 4096;
257
258   KeInitializeEvent(&Event,
259                     NotificationEvent,
260                     FALSE);
261
262   /* Write MBR (Master Boot Record) */
263   Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
264                                      DeviceObject,
265                                      Sector,
266                                      SectorSize,
267                                      SectorOffset,
268                                      &Event,
269                                      &StatusBlock);
270
271   Status = IoCallDriver(DeviceObject,
272                         Irp);
273   if (Status == STATUS_PENDING)
274     {
275       KeWaitForSingleObject(&Event,
276                             Executive,
277                             KernelMode,
278                             FALSE,
279                             NULL);
280       Status = StatusBlock.Status;
281     }
282
283   if (!NT_SUCCESS(Status))
284     {
285       DPRINT("Writing MBR failed (Status 0x%08lx)\n",
286              Status);
287       return Status;
288     }
289
290   return Status;
291 }
292
293
294 VOID FASTCALL
295 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
296                IN ULONG SectorSize,
297                IN ULONG MBRTypeIdentifier,
298                OUT PVOID *Buffer)
299 {
300   LARGE_INTEGER SectorOffset;
301   PPARTITION_SECTOR Sector;
302   PULONG Shift;
303   NTSTATUS Status;
304
305   DPRINT("xHalExamineMBR()\n");
306
307   *Buffer = NULL;
308
309   SectorOffset.QuadPart = 0ULL;
310   Status = xHalpReadSector(DeviceObject,
311                            SectorSize,
312                            &SectorOffset,
313                            (PVOID *)&Sector);
314   if (!NT_SUCCESS(Status))
315     {
316       DPRINT1("xHalpReadSector() failed (Status %lx)\n", Status);
317       return;
318     }
319
320   if (Sector->Magic != PARTITION_MAGIC)
321     {
322       DPRINT("Invalid MBR magic value\n");
323       ExFreePool(Sector);
324       return;
325     }
326
327   if (Sector->Partition[0].PartitionType != MBRTypeIdentifier)
328     {
329       DPRINT("Invalid MBRTypeIdentifier\n");
330       ExFreePool(Sector);
331       return;
332     }
333
334   if (Sector->Partition[0].PartitionType == 0x54)
335     {
336       /* Found 'Ontrack Disk Manager'. Shift all sectors by 63 */
337       DPRINT("Found 'Ontrack Disk Manager'!\n");
338       Shift = (PULONG)Sector;
339       *Shift = 63;
340     }
341
342   *Buffer = (PVOID)Sector;
343 }
344
345
346 static VOID
347 HalpAssignDrive(IN PUNICODE_STRING PartitionName,
348                 IN ULONG DriveNumber,
349                 IN UCHAR DriveType)
350 {
351   WCHAR DriveNameBuffer[8];
352   UNICODE_STRING DriveName;
353   ULONG i;
354
355   DPRINT("HalpAssignDrive()\n");
356
357   if ((DriveNumber != AUTO_DRIVE) && (DriveNumber < 24))
358     {
359       /* Force assignment */
360       if ((SharedUserData->DosDeviceMap & (1 << DriveNumber)) != 0)
361         {
362           DbgPrint("Drive letter already used!\n");
363           return;
364         }
365     }
366   else
367     {
368       /* Automatic assignment */
369       DriveNumber = AUTO_DRIVE;
370
371       for (i = 2; i < 24; i++)
372         {
373           if ((SharedUserData->DosDeviceMap & (1 << i)) == 0)
374             {
375               DriveNumber = i;
376               break;
377             }
378         }
379
380       if (DriveNumber == AUTO_DRIVE)
381         {
382           DbgPrint("No drive letter available!\n");
383           return;
384         }
385     }
386
387   DPRINT("DriveNumber %d\n", DriveNumber);
388
389   /* Update the shared user page */
390   SharedUserData->DosDeviceMap |= (1 << DriveNumber);
391   SharedUserData->DosDeviceDriveType[DriveNumber] = DriveType;
392
393   /* Build drive name */
394   swprintf(DriveNameBuffer,
395            L"\\??\\%C:",
396            'A' + DriveNumber);
397   RtlInitUnicodeString(&DriveName,
398                        DriveNameBuffer);
399
400   DPRINT("  %wZ ==> %wZ\n",
401          &DriveName,
402          PartitionName);
403
404   /* Create symbolic link */
405   IoCreateSymbolicLink(&DriveName,
406                        PartitionName);
407 }
408
409
410 VOID FASTCALL
411 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
412                          IN PSTRING NtDeviceName,
413                          OUT PUCHAR NtSystemPath,
414                          OUT PSTRING NtSystemPathString)
415 {
416   PDRIVE_LAYOUT_INFORMATION *LayoutArray;
417   PCONFIGURATION_INFORMATION ConfigInfo;
418   OBJECT_ATTRIBUTES ObjectAttributes;
419   IO_STATUS_BLOCK StatusBlock;
420   UNICODE_STRING UnicodeString1;
421   UNICODE_STRING UnicodeString2;
422   HANDLE FileHandle;
423   PWSTR Buffer1;
424   PWSTR Buffer2;
425   ULONG i;
426   NTSTATUS Status;
427   ULONG j;
428
429   DPRINT("xHalIoAssignDriveLetters()\n");
430
431   ConfigInfo = IoGetConfigurationInformation();
432
433   Buffer1 = (PWSTR)ExAllocatePool(PagedPool,
434                                   64 * sizeof(WCHAR));
435   Buffer2 = (PWSTR)ExAllocatePool(PagedPool,
436                                   32 * sizeof(WCHAR));
437
438   /* Create PhysicalDrive links */
439   DPRINT("Physical disk drives: %d\n", ConfigInfo->DiskCount);
440   for (i = 0; i < ConfigInfo->DiskCount; i++)
441     {
442       swprintf(Buffer1,
443                L"\\Device\\Harddisk%d\\Partition0",
444                 i);
445       RtlInitUnicodeString(&UnicodeString1,
446                            Buffer1);
447
448       InitializeObjectAttributes(&ObjectAttributes,
449                                  &UnicodeString1,
450                                  0,
451                                  NULL,
452                                  NULL);
453
454       Status = NtOpenFile(&FileHandle,
455                           0x10001,
456                           &ObjectAttributes,
457                           &StatusBlock,
458                           1,
459                           FILE_SYNCHRONOUS_IO_NONALERT);
460       if (NT_SUCCESS(Status))
461         {
462           NtClose(FileHandle);
463
464           swprintf(Buffer2,
465                    L"\\??\\PhysicalDrive%d",
466                    i);
467           RtlInitUnicodeString(&UnicodeString2,
468                                Buffer2);
469
470           DPRINT("Creating link: %S ==> %S\n",
471                  Buffer2,
472                  Buffer1);
473
474           IoCreateSymbolicLink(&UnicodeString2,
475                                &UnicodeString1);
476         }
477     }
478
479   /* Initialize layout array */
480   LayoutArray = ExAllocatePool(NonPagedPool,
481                                ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
482   RtlZeroMemory(LayoutArray,
483                 ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
484   for (i = 0; i < ConfigInfo->DiskCount; i++)
485     {
486       swprintf(Buffer1,
487                L"\\Device\\Harddisk%d\\Partition0",
488                i);
489       RtlInitUnicodeString(&UnicodeString1,
490                            Buffer1);
491
492       Status = xHalQueryDriveLayout(&UnicodeString1,
493                                     &LayoutArray[i]);
494       if (!NT_SUCCESS(Status))
495         {
496           DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n",
497                    Status);
498           LayoutArray[i] = NULL;
499           continue;
500         }
501     }
502
503 #ifndef NDEBUG
504   /* Dump layout array */
505   for (i = 0; i < ConfigInfo->DiskCount; i++)
506     {
507       DPRINT("Harddisk %d:\n",
508              i);
509
510       if (LayoutArray[i] == NULL)
511         continue;
512
513       DPRINT("Logical partitions: %d\n",
514              LayoutArray[i]->PartitionCount);
515
516       for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
517         {
518           DPRINT("  %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n",
519                  j,
520                  LayoutArray[i]->PartitionEntry[j].PartitionNumber,
521                  LayoutArray[i]->PartitionEntry[j].BootIndicator,
522                  LayoutArray[i]->PartitionEntry[j].PartitionType,
523                  LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart,
524                  LayoutArray[i]->PartitionEntry[j].PartitionLength.QuadPart);
525         }
526     }
527 #endif
528
529   /* Assign pre-assigned (registry) partitions */
530
531
532   /* Assign bootable partition on first harddisk */
533   DPRINT("Assigning bootable primary partition on first harddisk:\n");
534   if (ConfigInfo->DiskCount > 0)
535     {
536       /* Search for bootable partition */
537       for (j = 0; j < LayoutArray[0]->PartitionCount; j++)
538         {
539           if ((LayoutArray[0]->PartitionEntry[j].BootIndicator == TRUE) &&
540               IsRecognizedPartition(LayoutArray[0]->PartitionEntry[j].PartitionType))
541             {
542               swprintf(Buffer2,
543                        L"\\Device\\Harddisk0\\Partition%d",
544                        LayoutArray[0]->PartitionEntry[j].PartitionNumber);
545               RtlInitUnicodeString(&UnicodeString2,
546                                    Buffer2);
547
548               /* Assign drive */
549               DPRINT("  %wZ\n", &UnicodeString2);
550               HalpAssignDrive(&UnicodeString2,
551                               AUTO_DRIVE,
552                               DOSDEVICE_DRIVE_FIXED);
553             }
554         }
555     }
556
557   /* Assign remaining  primary partitions */
558   DPRINT("Assigning remaining primary partitions:\n");
559   for (i = 0; i < ConfigInfo->DiskCount; i++)
560     {
561       /* Search for primary partitions */
562       for (j = 0; (j < PARTITION_TBL_SIZE) && (j < LayoutArray[i]->PartitionCount); j++)
563         {
564           if ((i == 0) && (LayoutArray[i]->PartitionEntry[j].BootIndicator == TRUE))
565             continue;
566
567           if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType))
568             {
569               swprintf(Buffer2,
570                        L"\\Device\\Harddisk%d\\Partition%d",
571                        i,
572                        LayoutArray[i]->PartitionEntry[j].PartitionNumber);
573               RtlInitUnicodeString(&UnicodeString2,
574                                    Buffer2);
575
576               /* Assign drive */
577               DPRINT("  %wZ\n",
578                      &UnicodeString2);
579               HalpAssignDrive(&UnicodeString2,
580                               AUTO_DRIVE,
581                               DOSDEVICE_DRIVE_FIXED);
582             }
583         }
584     }
585
586   /* Assign extended (logical) partitions */
587   DPRINT("Assigning extended (logical) partitions:\n");
588   for (i = 0; i < ConfigInfo->DiskCount; i++)
589     {
590       if (LayoutArray[i])
591         {
592           /* Search for extended partitions */
593           for (j = PARTITION_TBL_SIZE; j < LayoutArray[i]->PartitionCount; j++)
594             {
595               if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType) &&
596                   (LayoutArray[i]->PartitionEntry[j].PartitionNumber != 0))
597                 {
598                   swprintf(Buffer2,
599                            L"\\Device\\Harddisk%d\\Partition%d",
600                            i,
601                            LayoutArray[i]->PartitionEntry[j].PartitionNumber);
602                   RtlInitUnicodeString(&UnicodeString2,
603                                        Buffer2);
604
605                   /* Assign drive */
606                   DPRINT("  %wZ\n",
607                          &UnicodeString2);
608                   HalpAssignDrive(&UnicodeString2,
609                                   AUTO_DRIVE,
610                                   DOSDEVICE_DRIVE_FIXED);
611                 }
612             }
613         }
614     }
615
616   /* Assign removable disk drives */
617   DPRINT("Assigning removable disk drives:\n");
618   for (i = 0; i < ConfigInfo->DiskCount; i++)
619     {
620       /* Search for virtual partitions */
621       if (LayoutArray[i]->PartitionCount == 1 &&
622           LayoutArray[i]->PartitionEntry[0].PartitionType == 0)
623         {
624           swprintf(Buffer2,
625                    L"\\Device\\Harddisk%d\\Partition1",
626                    i);
627           RtlInitUnicodeString(&UnicodeString2,
628                                Buffer2);
629
630           /* Assign drive */
631           DPRINT("  %wZ\n",
632                  &UnicodeString2);
633           HalpAssignDrive(&UnicodeString2,
634                           AUTO_DRIVE,
635                           DOSDEVICE_DRIVE_REMOVABLE);
636         }
637     }
638
639   /* Free layout array */
640   for (i = 0; i < ConfigInfo->DiskCount; i++)
641     {
642       if (LayoutArray[i] != NULL)
643         ExFreePool(LayoutArray[i]);
644     }
645   ExFreePool(LayoutArray);
646
647   /* Assign floppy drives */
648   DPRINT("Floppy drives: %d\n", ConfigInfo->FloppyCount);
649   for (i = 0; i < ConfigInfo->FloppyCount; i++)
650     {
651       swprintf(Buffer1,
652                L"\\Device\\Floppy%d",
653                i);
654       RtlInitUnicodeString(&UnicodeString1,
655                            Buffer1);
656
657       /* Assign drive letters A: or B: or first free drive letter */
658       DPRINT("  %wZ\n",
659              &UnicodeString1);
660       HalpAssignDrive(&UnicodeString1,
661                       (i < 2) ? i : AUTO_DRIVE,
662                       DOSDEVICE_DRIVE_REMOVABLE);
663     }
664
665   /* Assign cdrom drives */
666   DPRINT("CD-Rom drives: %d\n", ConfigInfo->CDRomCount);
667   for (i = 0; i < ConfigInfo->CDRomCount; i++)
668     {
669       swprintf(Buffer1,
670                L"\\Device\\CdRom%d",
671                i);
672       RtlInitUnicodeString(&UnicodeString1,
673                            Buffer1);
674
675       /* Assign first free drive letter */
676       DPRINT("  %wZ\n", &UnicodeString1);
677       HalpAssignDrive(&UnicodeString1,
678                       AUTO_DRIVE,
679                       DOSDEVICE_DRIVE_CDROM);
680     }
681
682   /* Anything else ?? */
683
684   ExFreePool(Buffer2);
685   ExFreePool(Buffer1);
686 }
687
688
689 NTSTATUS FASTCALL
690 xHalIoReadPartitionTable(PDEVICE_OBJECT DeviceObject,
691                          ULONG SectorSize,
692                          BOOLEAN ReturnRecognizedPartitions,
693                          PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
694 {
695   KEVENT Event;
696   IO_STATUS_BLOCK StatusBlock;
697   ULARGE_INTEGER PartitionOffset;
698   ULARGE_INTEGER RealPartitionOffset;
699   ULARGE_INTEGER nextPartitionOffset;
700   ULARGE_INTEGER containerOffset;
701   PIRP Irp;
702   NTSTATUS Status;
703   PPARTITION_SECTOR PartitionSector;
704   PDRIVE_LAYOUT_INFORMATION LayoutBuffer;
705   ULONG i;
706   ULONG Count = 0;
707   ULONG Number = 1;
708   BOOLEAN ExtendedFound = FALSE;
709   PVOID MbrBuffer;
710   DISK_MANAGER DiskManager = NoDiskManager;
711
712   DPRINT("xHalIoReadPartitionTable(%p %lu %x %p)\n",
713          DeviceObject,
714          SectorSize,
715          ReturnRecognizedPartitions,
716          PartitionBuffer);
717
718   *PartitionBuffer = NULL;
719
720   /* Check for 'Ontrack Disk Manager' */
721   xHalExamineMBR(DeviceObject,
722                  SectorSize,
723                  0x54,
724                  &MbrBuffer);
725   if (MbrBuffer != NULL)
726     {
727       DPRINT("Found 'Ontrack Disk Manager'\n");
728       DiskManager = OntrackDiskManager;
729       ExFreePool(MbrBuffer);
730     }
731
732   /* Check for 'EZ-Drive' */
733   xHalExamineMBR(DeviceObject,
734                  SectorSize,
735                  0x55,
736                  &MbrBuffer);
737   if (MbrBuffer != NULL)
738     {
739       DPRINT("Found 'EZ-Drive'\n");
740       DiskManager = EZ_Drive;
741       ExFreePool(MbrBuffer);
742     }
743
744   PartitionSector = (PPARTITION_SECTOR)ExAllocatePool(PagedPool,
745                                                       SectorSize);
746   if (PartitionSector == NULL)
747     {
748       return(STATUS_INSUFFICIENT_RESOURCES);
749     }
750
751   LayoutBuffer = (PDRIVE_LAYOUT_INFORMATION)ExAllocatePool(NonPagedPool,
752                                                            0x1000);
753   if (LayoutBuffer == NULL)
754     {
755       ExFreePool(PartitionSector);
756       return(STATUS_INSUFFICIENT_RESOURCES);
757     }
758
759   RtlZeroMemory(LayoutBuffer,
760                 0x1000);
761
762   PartitionOffset.QuadPart = (ULONGLONG)0;
763   containerOffset.QuadPart = (ULONGLONG)0;
764
765   do
766     {
767       DPRINT("PartitionOffset: %I64u\n", PartitionOffset.QuadPart / SectorSize);
768
769       if (DiskManager == OntrackDiskManager)
770         {
771           RealPartitionOffset.QuadPart = PartitionOffset.QuadPart + (ULONGLONG)(63 * SectorSize);
772         }
773       else
774         {
775           RealPartitionOffset.QuadPart = PartitionOffset.QuadPart;
776         }
777
778       DPRINT("RealPartitionOffset: %I64u\n", RealPartitionOffset.QuadPart / SectorSize);
779
780       KeInitializeEvent(&Event,
781                         NotificationEvent,
782                         FALSE);
783
784       Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
785                                          DeviceObject,
786                                          PartitionSector, //SectorBuffer,
787                                          SectorSize,
788                                          (PLARGE_INTEGER)&RealPartitionOffset,
789                                          &Event,
790                                          &StatusBlock);
791       Status = IoCallDriver(DeviceObject,
792                             Irp);
793       if (Status == STATUS_PENDING)
794         {
795           KeWaitForSingleObject(&Event,
796                                 Executive,
797                                 KernelMode,
798                                 FALSE,
799                                 NULL);
800           Status = StatusBlock.Status;
801         }
802
803       if (!NT_SUCCESS(Status))
804         {
805           DPRINT("Failed to read partition table sector (Status = 0x%08lx)\n",
806                  Status);
807           ExFreePool(PartitionSector);
808           ExFreePool(LayoutBuffer);
809           return(Status);
810         }
811
812       /* check the boot sector id */
813       DPRINT("Magic %x\n", PartitionSector->Magic);
814       if (PartitionSector->Magic != PARTITION_MAGIC)
815         {
816           DbgPrint("Invalid partition sector magic\n");
817           ExFreePool(PartitionSector);
818           *PartitionBuffer = LayoutBuffer;
819           return(STATUS_SUCCESS);
820         }
821
822 #ifndef NDEBUG
823       for (i = 0; i < PARTITION_TBL_SIZE; i++)
824         {
825           DPRINT1("  %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
826                   i,
827                   PartitionSector->Partition[i].BootFlags,
828                   PartitionSector->Partition[i].PartitionType,
829                   PartitionSector->Partition[i].StartingHead,
830                   PartitionSector->Partition[i].StartingSector & 0x3f,
831                   (((PartitionSector->Partition[i].StartingSector) & 0xc0) << 2) +
832                      PartitionSector->Partition[i].StartingCylinder,
833                   PartitionSector->Partition[i].EndingHead,
834                   PartitionSector->Partition[i].EndingSector,
835                   PartitionSector->Partition[i].EndingCylinder,
836                   PartitionSector->Partition[i].StartingBlock,
837                   PartitionSector->Partition[i].SectorCount);
838         }
839 #endif
840
841       if (PartitionOffset.QuadPart == 0ULL)
842         {
843           LayoutBuffer->Signature = PartitionSector->Signature;
844           DPRINT("Disk signature: %lx\n", LayoutBuffer->Signature);
845         }
846
847       ExtendedFound = FALSE;
848
849       for (i = 0; i < PARTITION_TBL_SIZE; i++)
850         {
851           if ((ReturnRecognizedPartitions == FALSE) ||
852                ((ReturnRecognizedPartitions == TRUE) &&
853                 IsRecognizedPartition(PartitionSector->Partition[i].PartitionType)))
854             {
855               /* handle normal partition */
856               DPRINT("Partition %u: Normal Partition\n", i);
857               Count = LayoutBuffer->PartitionCount;
858               DPRINT("Logical Partition %u\n", Count);
859               if (PartitionSector->Partition[i].StartingBlock == 0)
860                 {
861                   LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart = 0;
862                 }
863               else if (IsContainerPartition(PartitionSector->Partition[i].PartitionType))
864                 {
865                   LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart =
866                     (ULONGLONG)PartitionOffset.QuadPart;
867                 }
868               else
869                 {
870                   LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart =
871                     (ULONGLONG)PartitionOffset.QuadPart +
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 = 0;
877
878               if (IsRecognizedPartition(PartitionSector->Partition[i].PartitionType))
879                 {
880                   LayoutBuffer->PartitionEntry[Count].PartitionNumber = Number;
881                   Number++;
882                 }
883               else
884                 {
885                   LayoutBuffer->PartitionEntry[Count].PartitionNumber = 0;
886                 }
887
888               LayoutBuffer->PartitionEntry[Count].PartitionType =
889                 PartitionSector->Partition[i].PartitionType;
890               LayoutBuffer->PartitionEntry[Count].BootIndicator =
891                 (PartitionSector->Partition[i].BootFlags & 0x80)?TRUE:FALSE;
892               LayoutBuffer->PartitionEntry[Count].RecognizedPartition =
893                 IsRecognizedPartition (PartitionSector->Partition[i].PartitionType);
894               LayoutBuffer->PartitionEntry[Count].RewritePartition = FALSE;
895
896               DPRINT(" %ld: nr: %d boot: %1x type: %x start: 0x%I64x count: 0x%I64x\n",
897                      Count,
898                      LayoutBuffer->PartitionEntry[Count].PartitionNumber,
899                      LayoutBuffer->PartitionEntry[Count].BootIndicator,
900                      LayoutBuffer->PartitionEntry[Count].PartitionType,
901                      LayoutBuffer->PartitionEntry[Count].StartingOffset.QuadPart,
902                      LayoutBuffer->PartitionEntry[Count].PartitionLength.QuadPart);
903
904               LayoutBuffer->PartitionCount++;
905             }
906
907           if (IsContainerPartition(PartitionSector->Partition[i].PartitionType))
908             {
909               ExtendedFound = TRUE;
910               if ((ULONGLONG) containerOffset.QuadPart == (ULONGLONG) 0)
911                 {
912                   containerOffset = PartitionOffset;
913                 }
914               nextPartitionOffset.QuadPart = (ULONGLONG) containerOffset.QuadPart +
915                 (ULONGLONG) PartitionSector->Partition[i].StartingBlock *
916                 (ULONGLONG) SectorSize;
917             }
918         }
919       PartitionOffset = nextPartitionOffset;
920     }
921   while (ExtendedFound == TRUE);
922
923   *PartitionBuffer = LayoutBuffer;
924   ExFreePool(PartitionSector);
925
926   return(STATUS_SUCCESS);
927 }
928
929
930 NTSTATUS FASTCALL
931 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
932                               IN ULONG SectorSize,
933                               IN ULONG PartitionNumber,
934                               IN ULONG PartitionType)
935 {
936   return(STATUS_NOT_IMPLEMENTED);
937 }
938
939
940 NTSTATUS FASTCALL
941 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
942                           IN ULONG SectorSize,
943                           IN ULONG SectorsPerTrack,
944                           IN ULONG NumberOfHeads,
945                           IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
946 {
947   PPARTITION_SECTOR PartitionSector;
948   LARGE_INTEGER SectorOffset;
949   NTSTATUS Status;
950   ULONG i;
951
952   DPRINT("xHalIoWritePartitionTable(%p %lu %lu %p)\n",
953          DeviceObject,
954          SectorSize,
955          SectorsPerTrack,
956          PartitionBuffer);
957
958   assert(DeviceObject);
959   assert(PartitionBuffer);
960
961   /* Check for 'Ontrack Disk Manager' */
962   xHalExamineMBR(DeviceObject,
963                  SectorSize,
964                  0x54,
965                  (PVOID *) &PartitionSector);
966   if (PartitionSector != NULL)
967     {
968       DPRINT1("Ontrack Disk Manager is not supported\n");
969       ExFreePool(PartitionSector);
970       return STATUS_UNSUCCESSFUL;
971     }
972
973   /* Check for 'EZ-Drive' */
974   xHalExamineMBR(DeviceObject,
975                  SectorSize,
976                  0x55,
977                  (PVOID *) &PartitionSector);
978   if (PartitionSector != NULL)
979     {
980       DPRINT1("EZ-Drive is not supported\n");
981       ExFreePool(PartitionSector);
982       return STATUS_UNSUCCESSFUL;
983     }
984
985
986   for (i = 0; i < PartitionBuffer->PartitionCount; i++)
987     {
988       if (IsContainerPartition(PartitionBuffer->PartitionEntry[i].PartitionType))
989         {
990           /* FIXME: Implement */
991           DPRINT1("Writing MBRs with extended partitions is not implemented\n");
992           return STATUS_UNSUCCESSFUL;
993         }
994     }
995
996
997   SectorOffset.QuadPart = 0ULL;
998   Status = xHalpReadSector(DeviceObject,
999                            SectorSize,
1000                            &SectorOffset,
1001                            (PVOID *) &PartitionSector);
1002     if (!NT_SUCCESS(Status))
1003     {
1004       DPRINT1("xHalpReadSector() failed (Status %lx)\n", Status);
1005       return Status;
1006     }
1007
1008   DPRINT1("WARNING: Only 'BootFlags' is implemented\n");
1009
1010
1011   for (i = 0; i < PartitionBuffer->PartitionCount; i++)
1012     {
1013       //= PartitionBuffer->PartitionEntry[i].StartingOffset;
1014       //= PartitionBuffer->PartitionEntry[i].PartitionLength;
1015       //= PartitionBuffer->PartitionEntry[i].HiddenSectors;
1016       //= PartitionBuffer->PartitionEntry[i].PartitionType;
1017       //= PartitionBuffer->PartitionEntry[i].PartitionType;
1018
1019       if (PartitionBuffer->PartitionEntry[i].BootIndicator)
1020         {
1021           PartitionSector->Partition[i].BootFlags |= 0x80;
1022         }
1023       else
1024         {
1025           PartitionSector->Partition[i].BootFlags &= ~0x80;
1026         }
1027
1028       //= PartitionBuffer->PartitionEntry[i].RecognizedPartition;
1029       //= PartitionBuffer->PartitionEntry[i].RewritePartition;
1030     }
1031
1032
1033   SectorOffset.QuadPart = 0ULL;
1034   Status = xHalpWriteSector(DeviceObject,
1035                             SectorSize,
1036                             &SectorOffset,
1037                             (PVOID) PartitionSector);
1038   if (!NT_SUCCESS(Status))
1039     {
1040       DPRINT1("xHalpWriteSector() failed (Status %lx)\n", Status);
1041       ExFreePool(PartitionSector);
1042       return Status;
1043     }
1044
1045 #ifndef NDEBUG
1046       for (i = 0; i < PARTITION_TBL_SIZE; i++)
1047         {
1048           DPRINT1("  %d: flags:%2x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n",
1049                   i,
1050                   PartitionSector->Partition[i].BootFlags,
1051                   PartitionSector->Partition[i].PartitionType,
1052                   PartitionSector->Partition[i].StartingHead,
1053                   PartitionSector->Partition[i].StartingSector & 0x3f,
1054                   (((PartitionSector->Partition[i].StartingSector) & 0xc0) << 2) +
1055                      PartitionSector->Partition[i].StartingCylinder,
1056                   PartitionSector->Partition[i].EndingHead,
1057                   PartitionSector->Partition[i].EndingSector,
1058                   PartitionSector->Partition[i].EndingCylinder,
1059                   PartitionSector->Partition[i].StartingBlock,
1060                   PartitionSector->Partition[i].SectorCount);
1061         }
1062 #endif
1063
1064   ExFreePool(PartitionSector);
1065
1066   return(STATUS_SUCCESS);
1067 }
1068
1069 /* EOF */