xref: /reactos/ntoskrnl/fstub/disksup.c (revision 3c774903)
1 /*
2 * PROJECT:         ReactOS Kernel
3 * LICENSE:         GPL - See COPYING in the top level directory
4 * FILE:            ntoskrnl/fstub/disksup.c
5 * PURPOSE:         I/O HAL Routines for Disk Access
6 * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7 *                  Eric Kohl
8 *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
9 */
10 
11 /* INCLUDES ******************************************************************/
12 
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16 #include <internal/hal.h>
17 
18 /* DEPRECATED FUNCTIONS ******************************************************/
19 
20 #if 1
21 const WCHAR DiskMountString[] = L"\\DosDevices\\%C:";
22 
23 #define AUTO_DRIVE         MAXULONG
24 
25 #define PARTITION_MAGIC    0xaa55
26 
27 #define EFI_PMBR_OSTYPE_EFI 0xEE
28 
29 #include <pshpack1.h>
30 
31 typedef struct _REG_DISK_MOUNT_INFO
32 {
33     ULONG Signature;
34     LARGE_INTEGER StartingOffset;
35 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO;
36 
37 #include <poppack.h>
38 
39 typedef enum _DISK_MANAGER
40 {
41     NoDiskManager,
42     OntrackDiskManager,
43     EZ_Drive
44 } DISK_MANAGER;
45 
46 static BOOLEAN
47 HalpAssignDrive(IN PUNICODE_STRING PartitionName,
48                 IN ULONG DriveNumber,
49                 IN UCHAR DriveType,
50                 IN ULONG Signature,
51                 IN LARGE_INTEGER StartingOffset,
52                 IN HANDLE hKey,
53                 IN PUNICODE_STRING BootDevice,
54                 OUT PUCHAR NtSystemPath)
55 {
56     WCHAR DriveNameBuffer[16];
57     UNICODE_STRING DriveName;
58     ULONG i;
59     NTSTATUS Status;
60     REG_DISK_MOUNT_INFO DiskMountInfo;
61 
62     DPRINT("HalpAssignDrive()\n");
63 
64     if ((DriveNumber != AUTO_DRIVE) && (DriveNumber < 26))
65     {
66         /* Force assignment */
67         KeAcquireGuardedMutex(&ObpDeviceMapLock);
68         if ((ObSystemDeviceMap->DriveMap & (1 << DriveNumber)) != 0)
69         {
70             DbgPrint("Drive letter already used!\n");
71             KeReleaseGuardedMutex(&ObpDeviceMapLock);
72             return FALSE;
73         }
74         KeReleaseGuardedMutex(&ObpDeviceMapLock);
75     }
76     else
77     {
78         /* Automatic assignment */
79         DriveNumber = AUTO_DRIVE;
80         KeAcquireGuardedMutex(&ObpDeviceMapLock);
81         for (i = 2; i < 26; i++)
82         {
83             if ((ObSystemDeviceMap->DriveMap & (1 << i)) == 0)
84             {
85                 DriveNumber = i;
86                 break;
87             }
88         }
89         KeReleaseGuardedMutex(&ObpDeviceMapLock);
90 
91         if (DriveNumber == AUTO_DRIVE)
92         {
93             DbgPrint("No drive letter available!\n");
94             return FALSE;
95         }
96     }
97 
98     DPRINT("DriveNumber %lu\n", DriveNumber);
99 
100     /* Build drive name */
101     swprintf(DriveNameBuffer,
102         L"\\??\\%C:",
103         'A' + DriveNumber);
104     RtlInitUnicodeString(&DriveName,
105         DriveNameBuffer);
106 
107     DPRINT("  %wZ ==> %wZ\n",
108         &DriveName,
109         PartitionName);
110 
111     /* Create symbolic link */
112     Status = IoCreateSymbolicLink(&DriveName,
113         PartitionName);
114 
115     if (hKey &&
116         DriveType == DOSDEVICE_DRIVE_FIXED &&
117         Signature)
118     {
119         DiskMountInfo.Signature = Signature;
120         DiskMountInfo.StartingOffset = StartingOffset;
121         swprintf(DriveNameBuffer, DiskMountString, L'A' + DriveNumber);
122         RtlInitUnicodeString(&DriveName, DriveNameBuffer);
123 
124         Status = ZwSetValueKey(hKey,
125             &DriveName,
126             0,
127             REG_BINARY,
128             &DiskMountInfo,
129             sizeof(DiskMountInfo));
130         if (!NT_SUCCESS(Status))
131         {
132             DPRINT1("ZwCreateValueKey failed for %wZ, status=%x\n", &DriveName, Status);
133         }
134     }
135 
136     /* Check if this is a boot partition */
137     if (RtlCompareUnicodeString(PartitionName, BootDevice, FALSE) == 0)
138     {
139         /* Set NtSystemPath to that partition's disk letter */
140         *NtSystemPath = (UCHAR)('A' + DriveNumber);
141     }
142 
143     return TRUE;
144 }
145 
146 ULONG
147 xHalpGetRDiskCount(VOID)
148 {
149     NTSTATUS Status;
150     UNICODE_STRING ArcName;
151     PWCHAR ArcNameBuffer;
152     OBJECT_ATTRIBUTES ObjectAttributes;
153     HANDLE DirectoryHandle;
154     POBJECT_DIRECTORY_INFORMATION DirectoryInfo;
155     ULONG Skip;
156     ULONG ResultLength;
157     ULONG CurrentRDisk;
158     ULONG RDiskCount;
159     BOOLEAN First = TRUE;
160     ULONG Count;
161 
162     DirectoryInfo = ExAllocatePoolWithTag(PagedPool, 2 * PAGE_SIZE, TAG_FILE_SYSTEM);
163     if (DirectoryInfo == NULL)
164     {
165         return 0;
166     }
167 
168     RtlInitUnicodeString(&ArcName, L"\\ArcName");
169     InitializeObjectAttributes(&ObjectAttributes,
170         &ArcName,
171         0,
172         NULL,
173         NULL);
174 
175     Status = ZwOpenDirectoryObject (&DirectoryHandle,
176         DIRECTORY_ALL_ACCESS,
177         &ObjectAttributes);
178     if (!NT_SUCCESS(Status))
179     {
180         DPRINT1("ZwOpenDirectoryObject for %wZ failed, status=%lx\n", &ArcName, Status);
181         ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM);
182         return 0;
183     }
184 
185     RDiskCount = 0;
186     Skip = 0;
187     while (NT_SUCCESS(Status))
188     {
189         Status = ZwQueryDirectoryObject (DirectoryHandle,
190             DirectoryInfo,
191             2 * PAGE_SIZE,
192             FALSE,
193             First,
194             &Skip,
195             &ResultLength);
196         First = FALSE;
197         if (NT_SUCCESS(Status))
198         {
199             Count = 0;
200             while (DirectoryInfo[Count].Name.Buffer)
201             {
202                 DPRINT("Count %x\n", Count);
203                 DirectoryInfo[Count].Name.Buffer[DirectoryInfo[Count].Name.Length / sizeof(WCHAR)] = 0;
204                 ArcNameBuffer = DirectoryInfo[Count].Name.Buffer;
205                 if (DirectoryInfo[Count].Name.Length >= sizeof(L"multi(0)disk(0)rdisk(0)") - sizeof(WCHAR) &&
206                     !_wcsnicmp(ArcNameBuffer, L"multi(0)disk(0)rdisk(", (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR)))
207                 {
208                     DPRINT("%S\n", ArcNameBuffer);
209                     ArcNameBuffer += (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR);
210                     CurrentRDisk = 0;
211                     while (iswdigit(*ArcNameBuffer))
212                     {
213                         CurrentRDisk = CurrentRDisk * 10 + *ArcNameBuffer - L'0';
214                         ArcNameBuffer++;
215                     }
216                     if (!_wcsicmp(ArcNameBuffer, L")") &&
217                         CurrentRDisk >= RDiskCount)
218                     {
219                         RDiskCount = CurrentRDisk + 1;
220                     }
221                 }
222                 Count++;
223             }
224         }
225     }
226 
227     ZwClose(DirectoryHandle);
228 
229     ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM);
230     return RDiskCount;
231 }
232 
233 NTSTATUS
234 xHalpGetDiskNumberFromRDisk(ULONG RDisk, PULONG DiskNumber)
235 {
236     WCHAR NameBuffer[80];
237     UNICODE_STRING ArcName;
238     UNICODE_STRING LinkName;
239     OBJECT_ATTRIBUTES ObjectAttributes;
240     HANDLE LinkHandle;
241     NTSTATUS Status;
242 
243     swprintf(NameBuffer,
244         L"\\ArcName\\multi(0)disk(0)rdisk(%lu)",
245         RDisk);
246 
247     RtlInitUnicodeString(&ArcName, NameBuffer);
248     InitializeObjectAttributes(&ObjectAttributes,
249         &ArcName,
250         0,
251         NULL,
252         NULL);
253     Status = ZwOpenSymbolicLinkObject(&LinkHandle,
254         SYMBOLIC_LINK_ALL_ACCESS,
255         &ObjectAttributes);
256     if (!NT_SUCCESS(Status))
257     {
258         DPRINT1("ZwOpenSymbolicLinkObject failed for %wZ, status=%lx\n", &ArcName, Status);
259         return Status;
260     }
261 
262     LinkName.Buffer = NameBuffer;
263     LinkName.Length = 0;
264     LinkName.MaximumLength = sizeof(NameBuffer);
265     Status = ZwQuerySymbolicLinkObject(LinkHandle,
266         &LinkName,
267         NULL);
268     ZwClose(LinkHandle);
269     if (!NT_SUCCESS(Status))
270     {
271         DPRINT1("ZwQuerySymbolicLinkObject failed, status=%lx\n", Status);
272         return Status;
273     }
274     if (LinkName.Length < sizeof(L"\\Device\\Harddisk0\\Partition0") - sizeof(WCHAR) ||
275         LinkName.Length >= sizeof(NameBuffer))
276     {
277         return STATUS_UNSUCCESSFUL;
278     }
279 
280     NameBuffer[LinkName.Length / sizeof(WCHAR)] = 0;
281     if (_wcsnicmp(NameBuffer, L"\\Device\\Harddisk", (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR)))
282     {
283         return STATUS_UNSUCCESSFUL;
284     }
285     LinkName.Buffer += (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR);
286 
287     if (!iswdigit(*LinkName.Buffer))
288     {
289         return STATUS_UNSUCCESSFUL;
290     }
291     *DiskNumber = 0;
292     while (iswdigit(*LinkName.Buffer))
293     {
294         *DiskNumber = *DiskNumber * 10 + *LinkName.Buffer - L'0';
295         LinkName.Buffer++;
296     }
297     if (_wcsicmp(LinkName.Buffer, L"\\Partition0"))
298     {
299         return STATUS_UNSUCCESSFUL;
300     }
301     return STATUS_SUCCESS;
302 }
303 
304 NTSTATUS
305 FASTCALL
306 xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName,
307                      OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo)
308 {
309     IO_STATUS_BLOCK StatusBlock;
310     DISK_GEOMETRY DiskGeometry;
311     PDEVICE_OBJECT DeviceObject = NULL;
312     PFILE_OBJECT FileObject;
313     KEVENT Event;
314     PIRP Irp;
315     NTSTATUS Status;
316 
317     DPRINT("xHalpQueryDriveLayout %wZ %p\n",
318         DeviceName,
319         LayoutInfo);
320 
321     /* Get the drives sector size */
322     Status = IoGetDeviceObjectPointer(DeviceName,
323         FILE_READ_ATTRIBUTES,
324         &FileObject,
325         &DeviceObject);
326     if (!NT_SUCCESS(Status))
327     {
328         DPRINT("Status %x\n", Status);
329         return(Status);
330     }
331 
332     KeInitializeEvent(&Event,
333         NotificationEvent,
334         FALSE);
335 
336     Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
337         DeviceObject,
338         NULL,
339         0,
340         &DiskGeometry,
341         sizeof(DISK_GEOMETRY),
342         FALSE,
343         &Event,
344         &StatusBlock);
345     if (Irp == NULL)
346     {
347         ObDereferenceObject(FileObject);
348         return(STATUS_INSUFFICIENT_RESOURCES);
349     }
350 
351     Status = IoCallDriver(DeviceObject,
352         Irp);
353     if (Status == STATUS_PENDING)
354     {
355         KeWaitForSingleObject(&Event,
356             Executive,
357             KernelMode,
358             FALSE,
359             NULL);
360         Status = StatusBlock.Status;
361     }
362     if (!NT_SUCCESS(Status))
363     {
364         if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
365         {
366             DiskGeometry.BytesPerSector = 512;
367         }
368         else
369         {
370             ObDereferenceObject(FileObject);
371             return(Status);
372         }
373     }
374 
375     DPRINT("DiskGeometry.BytesPerSector: %lu\n",
376         DiskGeometry.BytesPerSector);
377 
378     if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
379     {
380         PDRIVE_LAYOUT_INFORMATION Buffer;
381 
382         /* Allocate a partition list for a single entry. */
383         Buffer = ExAllocatePoolWithTag(NonPagedPool,
384             sizeof(DRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM);
385         if (Buffer != NULL)
386         {
387             RtlZeroMemory(Buffer,
388                 sizeof(DRIVE_LAYOUT_INFORMATION));
389             Buffer->PartitionCount = 1;
390             *LayoutInfo = Buffer;
391 
392             Status = STATUS_SUCCESS;
393         }
394         else
395         {
396             Status = STATUS_UNSUCCESSFUL;
397         }
398     }
399     else
400     {
401         /* Read the partition table */
402         Status = IoReadPartitionTable(DeviceObject,
403             DiskGeometry.BytesPerSector,
404             TRUE,
405             LayoutInfo);
406     }
407 
408     ObDereferenceObject(FileObject);
409 
410     return(Status);
411 }
412 
413 VOID
414 FASTCALL
415 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
416                          IN PSTRING NtDeviceName,
417                          OUT PUCHAR NtSystemPath,
418                          OUT PSTRING NtSystemPathString)
419 {
420     PDRIVE_LAYOUT_INFORMATION *LayoutArray;
421     PCONFIGURATION_INFORMATION ConfigInfo;
422     OBJECT_ATTRIBUTES ObjectAttributes;
423     IO_STATUS_BLOCK StatusBlock;
424     UNICODE_STRING UnicodeString1;
425     UNICODE_STRING UnicodeString2;
426     HANDLE FileHandle;
427     PWSTR Buffer1;
428     PWSTR Buffer2;
429     ULONG i, j, k;
430     ULONG DiskNumber;
431     ULONG RDisk;
432     NTSTATUS Status;
433     HANDLE hKey;
434     ULONG Length;
435     PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
436     PREG_DISK_MOUNT_INFO DiskMountInfo;
437     ULONG RDiskCount;
438     UNICODE_STRING BootDevice;
439 
440     Status = RtlAnsiStringToUnicodeString(&BootDevice,
441                                           NtDeviceName,
442                                           TRUE);
443 
444     DPRINT("xHalIoAssignDriveLetters()\n");
445 
446     ConfigInfo = IoGetConfigurationInformation();
447 
448     RDiskCount = xHalpGetRDiskCount();
449 
450     DPRINT("RDiskCount %lu\n", RDiskCount);
451 
452     Buffer1 = ExAllocatePoolWithTag(PagedPool,
453         64 * sizeof(WCHAR),
454         TAG_FILE_SYSTEM);
455     if (!Buffer1) return;
456 
457     Buffer2 = ExAllocatePoolWithTag(PagedPool,
458         32 * sizeof(WCHAR),
459         TAG_FILE_SYSTEM);
460     if (!Buffer2)
461     {
462         ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
463         return;
464     }
465 
466     PartialInformation = ExAllocatePoolWithTag(PagedPool,
467         sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO),
468         TAG_FILE_SYSTEM);
469     if (!PartialInformation)
470     {
471         ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
472         ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
473         return;
474     }
475 
476     DiskMountInfo = (PREG_DISK_MOUNT_INFO) PartialInformation->Data;
477 
478     /* Create or open the 'MountedDevices' key */
479     RtlInitUnicodeString(&UnicodeString1, L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
480     InitializeObjectAttributes(&ObjectAttributes,
481         &UnicodeString1,
482         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
483         NULL,
484         NULL);
485     Status = ZwCreateKey(&hKey,
486         KEY_ALL_ACCESS,
487         &ObjectAttributes,
488         0,
489         NULL,
490         REG_OPTION_NON_VOLATILE,
491         NULL);
492     if (!NT_SUCCESS(Status))
493     {
494         hKey = NULL;
495         DPRINT("ZwCreateKey failed for %wZ, status=%x\n", &UnicodeString1, Status);
496     }
497 
498     /* Create PhysicalDrive links */
499     DPRINT("Physical disk drives: %lu\n", ConfigInfo->DiskCount);
500     for (i = 0; i < ConfigInfo->DiskCount; i++)
501     {
502         swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i);
503         RtlInitUnicodeString(&UnicodeString1, Buffer1);
504 
505         InitializeObjectAttributes(&ObjectAttributes,
506             &UnicodeString1,
507             0,
508             NULL,
509             NULL);
510 
511         Status = ZwOpenFile(&FileHandle,
512             FILE_READ_DATA | SYNCHRONIZE,
513             &ObjectAttributes,
514             &StatusBlock,
515             FILE_SHARE_READ,
516             FILE_SYNCHRONOUS_IO_NONALERT);
517         if (NT_SUCCESS(Status))
518         {
519             ZwClose(FileHandle);
520 
521             swprintf(Buffer2, L"\\??\\PhysicalDrive%lu", i);
522             RtlInitUnicodeString(&UnicodeString2, Buffer2);
523 
524             DPRINT("Creating link: %S ==> %S\n",
525                 Buffer2,
526                 Buffer1);
527 
528             IoCreateSymbolicLink(&UnicodeString2,
529                 &UnicodeString1);
530         }
531     }
532 
533     /* Initialize layout array */
534     if (ConfigInfo->DiskCount == 0)
535         goto end_assign_disks;
536     LayoutArray = ExAllocatePoolWithTag(NonPagedPool,
537         ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM);
538     if (!LayoutArray)
539     {
540         ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM);
541         ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
542         ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
543         if (hKey) ObCloseHandle(hKey, KernelMode);
544         return;
545     }
546 
547     RtlZeroMemory(LayoutArray,
548         ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
549     for (i = 0; i < ConfigInfo->DiskCount; i++)
550     {
551         swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i);
552         RtlInitUnicodeString(&UnicodeString1, Buffer1);
553 
554         Status = xHalQueryDriveLayout(&UnicodeString1, &LayoutArray[i]);
555         if (!NT_SUCCESS(Status))
556         {
557             DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n",
558                 Status);
559             LayoutArray[i] = NULL;
560             continue;
561         }
562         /* We don't use the RewritePartition value while mounting the disks.
563         * We use this value for marking pre-assigned (registry) partitions.
564         */
565         for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
566         {
567             LayoutArray[i]->PartitionEntry[j].RewritePartition = FALSE;
568         }
569     }
570 
571 #ifndef NDEBUG
572     /* Dump layout array */
573     for (i = 0; i < ConfigInfo->DiskCount; i++)
574     {
575         DPRINT("Harddisk %d:\n",
576             i);
577 
578         if (LayoutArray[i] == NULL)
579             continue;
580 
581         DPRINT("Logical partitions: %d\n",
582             LayoutArray[i]->PartitionCount);
583 
584         for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
585         {
586             DPRINT("  %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n",
587                 j,
588                 LayoutArray[i]->PartitionEntry[j].PartitionNumber,
589                 LayoutArray[i]->PartitionEntry[j].BootIndicator,
590                 LayoutArray[i]->PartitionEntry[j].PartitionType,
591                 LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart,
592                 LayoutArray[i]->PartitionEntry[j].PartitionLength.QuadPart);
593         }
594     }
595 #endif
596 
597     /* Assign pre-assigned (registry) partitions */
598     if (hKey)
599     {
600         for (k = 2; k < 26; k++)
601         {
602             swprintf(Buffer1, DiskMountString, L'A' + k);
603             RtlInitUnicodeString(&UnicodeString1, Buffer1);
604             Status = ZwQueryValueKey(hKey,
605                 &UnicodeString1,
606                 KeyValuePartialInformation,
607                 PartialInformation,
608                 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO),
609                 &Length);
610             if (NT_SUCCESS(Status) &&
611                 PartialInformation->Type == REG_BINARY &&
612                 PartialInformation->DataLength == sizeof(REG_DISK_MOUNT_INFO))
613             {
614                 DPRINT("%wZ => %08x:%08x%08x\n", &UnicodeString1, DiskMountInfo->Signature,
615                     DiskMountInfo->StartingOffset.u.HighPart, DiskMountInfo->StartingOffset.u.LowPart);
616                 {
617                     BOOLEAN Found = FALSE;
618                     for (i = 0; i < ConfigInfo->DiskCount; i++)
619                     {
620                         DPRINT("%x\n", LayoutArray[i]->Signature);
621                         if (LayoutArray[i] &&
622                             LayoutArray[i]->Signature &&
623                             LayoutArray[i]->Signature == DiskMountInfo->Signature)
624                         {
625                             for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
626                             {
627                                 if (LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart == DiskMountInfo->StartingOffset.QuadPart)
628                                 {
629                                     if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType) &&
630                                         LayoutArray[i]->PartitionEntry[j].RewritePartition == FALSE)
631                                     {
632                                         swprintf(Buffer2,
633                                                  L"\\Device\\Harddisk%lu\\Partition%lu",
634                                                  i,
635                                                  LayoutArray[i]->PartitionEntry[j].PartitionNumber);
636                                         RtlInitUnicodeString(&UnicodeString2, Buffer2);
637 
638                                         /* Assign drive */
639                                         DPRINT("  %wZ\n", &UnicodeString2);
640                                         Found = HalpAssignDrive(&UnicodeString2,
641                                             k,
642                                             DOSDEVICE_DRIVE_FIXED,
643                                             DiskMountInfo->Signature,
644                                             DiskMountInfo->StartingOffset,
645                                             NULL,
646                                             &BootDevice,
647                                             NtSystemPath);
648                                         /* Mark the partition as assigned */
649                                         LayoutArray[i]->PartitionEntry[j].RewritePartition = TRUE;
650                                     }
651                                     break;
652                                 }
653                             }
654                         }
655                     }
656                     if (Found == FALSE)
657                     {
658                         /* We didn't find a partition for this entry, remove them. */
659                         Status = ZwDeleteValueKey(hKey, &UnicodeString1);
660                     }
661                 }
662             }
663         }
664     }
665 
666     /* Assign bootable partition on first harddisk */
667     DPRINT("Assigning bootable primary partition on first harddisk:\n");
668     if (RDiskCount > 0)
669     {
670         Status = xHalpGetDiskNumberFromRDisk(0, &DiskNumber);
671         if (NT_SUCCESS(Status) &&
672             DiskNumber < ConfigInfo->DiskCount &&
673             LayoutArray[DiskNumber])
674         {
675             /* Search for bootable partition */
676             for (j = 0; j < NUM_PARTITION_TABLE_ENTRIES && j < LayoutArray[DiskNumber]->PartitionCount; j++)
677             {
678                 if ((LayoutArray[DiskNumber]->PartitionEntry[j].BootIndicator != FALSE) &&
679                     IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
680                 {
681                     if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE)
682                     {
683                         swprintf(Buffer2,
684                                  L"\\Device\\Harddisk%lu\\Partition%lu",
685                                  DiskNumber,
686                                  LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
687                         RtlInitUnicodeString(&UnicodeString2, Buffer2);
688 
689                         /* Assign drive */
690                         DPRINT("  %wZ\n", &UnicodeString2);
691                         HalpAssignDrive(&UnicodeString2,
692                             AUTO_DRIVE,
693                             DOSDEVICE_DRIVE_FIXED,
694                             LayoutArray[DiskNumber]->Signature,
695                             LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
696                             hKey,
697                             &BootDevice,
698                             NtSystemPath);
699                         /* Mark the partition as assigned */
700                         LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
701                     }
702                     break;
703                 }
704             }
705         }
706     }
707 
708     /* Assign remaining primary partitions */
709     DPRINT("Assigning remaining primary partitions:\n");
710     for (RDisk = 0; RDisk < RDiskCount; RDisk++)
711     {
712         Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber);
713         if (NT_SUCCESS(Status) &&
714             DiskNumber < ConfigInfo->DiskCount &&
715             LayoutArray[DiskNumber])
716         {
717             /* Search for primary partitions */
718             for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++)
719             {
720                 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
721                     IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
722                 {
723                     swprintf(Buffer2,
724                              L"\\Device\\Harddisk%lu\\Partition%lu",
725                              DiskNumber,
726                              LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
727                     RtlInitUnicodeString(&UnicodeString2, Buffer2);
728 
729                     /* Assign drive */
730                     DPRINT("  %wZ\n",
731                         &UnicodeString2);
732                     HalpAssignDrive(&UnicodeString2,
733                         AUTO_DRIVE,
734                         DOSDEVICE_DRIVE_FIXED,
735                         LayoutArray[DiskNumber]->Signature,
736                         LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
737                         hKey,
738                         &BootDevice,
739                         NtSystemPath);
740                     /* Mark the partition as assigned */
741                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
742                 }
743             }
744         }
745     }
746 
747     /* Assign extended (logical) partitions */
748     DPRINT("Assigning extended (logical) partitions:\n");
749     for (RDisk = 0; RDisk < RDiskCount; RDisk++)
750     {
751         Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber);
752         if (NT_SUCCESS(Status) &&
753             DiskNumber < ConfigInfo->DiskCount &&
754             LayoutArray[DiskNumber])
755         {
756             /* Search for extended partitions */
757             for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++)
758             {
759                 if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) &&
760                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
761                     LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0)
762                 {
763                     swprintf(Buffer2,
764                              L"\\Device\\Harddisk%lu\\Partition%lu",
765                              DiskNumber,
766                              LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
767                     RtlInitUnicodeString(&UnicodeString2, Buffer2);
768 
769                     /* Assign drive */
770                     DPRINT("  %wZ\n",
771                         &UnicodeString2);
772                     HalpAssignDrive(&UnicodeString2,
773                         AUTO_DRIVE,
774                         DOSDEVICE_DRIVE_FIXED,
775                         LayoutArray[DiskNumber]->Signature,
776                         LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
777                         hKey,
778                         &BootDevice,
779                         NtSystemPath);
780                     /* Mark the partition as assigned */
781                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
782                 }
783             }
784         }
785     }
786 
787     /* Assign remaining primary partitions without an arc-name */
788     DPRINT("Assigning remaining primary partitions:\n");
789     for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++)
790     {
791         if (LayoutArray[DiskNumber])
792         {
793             /* Search for primary partitions */
794             for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++)
795             {
796                 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
797                     IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
798                 {
799                     swprintf(Buffer2,
800                              L"\\Device\\Harddisk%lu\\Partition%lu",
801                              DiskNumber,
802                              LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
803                     RtlInitUnicodeString(&UnicodeString2, Buffer2);
804 
805                     /* Assign drive */
806                     DPRINT("  %wZ\n",
807                         &UnicodeString2);
808                     HalpAssignDrive(&UnicodeString2,
809                         AUTO_DRIVE,
810                         DOSDEVICE_DRIVE_FIXED,
811                         LayoutArray[DiskNumber]->Signature,
812                         LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
813                         hKey,
814                         &BootDevice,
815                         NtSystemPath);
816                     /* Mark the partition as assigned */
817                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
818                 }
819             }
820         }
821     }
822 
823     /* Assign extended (logical) partitions without an arc-name */
824     DPRINT("Assigning extended (logical) partitions:\n");
825     for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++)
826     {
827         if (LayoutArray[DiskNumber])
828         {
829             /* Search for extended partitions */
830             for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++)
831             {
832                 if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) &&
833                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
834                     LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0)
835                 {
836                     swprintf(Buffer2,
837                              L"\\Device\\Harddisk%lu\\Partition%lu",
838                              DiskNumber,
839                              LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
840                     RtlInitUnicodeString(&UnicodeString2, Buffer2);
841 
842                     /* Assign drive */
843                     DPRINT("  %wZ\n",
844                         &UnicodeString2);
845                     HalpAssignDrive(&UnicodeString2,
846                         AUTO_DRIVE,
847                         DOSDEVICE_DRIVE_FIXED,
848                         LayoutArray[DiskNumber]->Signature,
849                         LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
850                         hKey,
851                         &BootDevice,
852                         NtSystemPath);
853                     /* Mark the partition as assigned */
854                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
855                 }
856             }
857         }
858     }
859 
860     /* Assign removable disk drives */
861     DPRINT("Assigning removable disk drives:\n");
862     for (i = 0; i < ConfigInfo->DiskCount; i++)
863     {
864         if (LayoutArray[i])
865         {
866             /* Search for virtual partitions */
867             if (LayoutArray[i]->PartitionCount == 1 &&
868                 LayoutArray[i]->PartitionEntry[0].PartitionType == 0)
869             {
870                 swprintf(Buffer2, L"\\Device\\Harddisk%lu\\Partition1", i);
871                 RtlInitUnicodeString(&UnicodeString2, Buffer2);
872 
873                 /* Assign drive */
874                 DPRINT("  %wZ\n",
875                     &UnicodeString2);
876                 HalpAssignDrive(&UnicodeString2,
877                     AUTO_DRIVE,
878                     DOSDEVICE_DRIVE_REMOVABLE,
879                     0,
880                     RtlConvertLongToLargeInteger(0),
881                     hKey,
882                     &BootDevice,
883                     NtSystemPath);
884             }
885         }
886     }
887 
888     /* Free layout array */
889     for (i = 0; i < ConfigInfo->DiskCount; i++)
890     {
891         if (LayoutArray[i] != NULL)
892             ExFreePoolWithTag(LayoutArray[i], TAG_FILE_SYSTEM);
893     }
894     ExFreePoolWithTag(LayoutArray, TAG_FILE_SYSTEM);
895 end_assign_disks:
896 
897     /* Assign floppy drives */
898     DPRINT("Floppy drives: %lu\n", ConfigInfo->FloppyCount);
899     for (i = 0; i < ConfigInfo->FloppyCount; i++)
900     {
901         swprintf(Buffer1, L"\\Device\\Floppy%lu", i);
902         RtlInitUnicodeString(&UnicodeString1, Buffer1);
903 
904         /* Assign drive letters A: or B: or first free drive letter */
905         DPRINT("  %wZ\n",
906             &UnicodeString1);
907         HalpAssignDrive(&UnicodeString1,
908             (i < 2) ? i : AUTO_DRIVE,
909             DOSDEVICE_DRIVE_REMOVABLE,
910             0,
911             RtlConvertLongToLargeInteger(0),
912             hKey,
913             &BootDevice,
914             NtSystemPath);
915     }
916 
917     /* Assign cdrom drives */
918     DPRINT("CD-Rom drives: %lu\n", ConfigInfo->CdRomCount);
919     for (i = 0; i < ConfigInfo->CdRomCount; i++)
920     {
921         swprintf(Buffer1, L"\\Device\\CdRom%lu", i);
922         RtlInitUnicodeString(&UnicodeString1, Buffer1);
923 
924         /* Assign first free drive letter */
925         DPRINT("  %wZ\n", &UnicodeString1);
926         HalpAssignDrive(&UnicodeString1,
927             AUTO_DRIVE,
928             DOSDEVICE_DRIVE_CDROM,
929             0,
930             RtlConvertLongToLargeInteger(0),
931             hKey,
932             &BootDevice,
933             NtSystemPath);
934     }
935 
936     /* Anything else to do? */
937 
938     ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM);
939     ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
940     ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
941     if (hKey) ObCloseHandle(hKey, KernelMode);
942 }
943 
944 #endif
945 
946 /* PRIVATE FUNCTIONS *********************************************************/
947 
948 NTSTATUS
949 NTAPI
950 HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject,
951                     IN PDISK_GEOMETRY Geometry,
952                     OUT PULONGLONG RealSectorCount)
953 {
954     PIRP Irp;
955     IO_STATUS_BLOCK IoStatusBlock;
956     PKEVENT Event;
957     NTSTATUS Status;
958     PARTITION_INFORMATION PartitionInfo;
959     PAGED_CODE();
960 
961     /* Allocate a non-paged event */
962     Event = ExAllocatePoolWithTag(NonPagedPool,
963                                      sizeof(KEVENT),
964                                      TAG_FILE_SYSTEM);
965     if (!Event) return STATUS_INSUFFICIENT_RESOURCES;
966 
967     /* Initialize it */
968     KeInitializeEvent(Event, NotificationEvent, FALSE);
969 
970     /* Build the IRP */
971     Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
972                                              DeviceObject,
973                                              NULL,
974                                              0UL,
975                                              Geometry,
976                                              sizeof(DISK_GEOMETRY),
977                                              FALSE,
978                                              Event,
979                                              &IoStatusBlock);
980     if (!Irp)
981     {
982         /* Fail, free the event */
983         ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
984         return STATUS_INSUFFICIENT_RESOURCES;
985     }
986 
987     /* Call the driver and check if it's pending */
988     Status = IoCallDriver(DeviceObject, Irp);
989     if (Status == STATUS_PENDING)
990     {
991         /* Wait on the driver */
992         KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
993         Status = IoStatusBlock.Status;
994     }
995 
996     /* Check if the driver returned success */
997     if(NT_SUCCESS(Status))
998     {
999         /* Build another IRP */
1000         Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
1001                                                  DeviceObject,
1002                                                  NULL,
1003                                                  0UL,
1004                                                  &PartitionInfo,
1005                                                  sizeof(PARTITION_INFORMATION),
1006                                                  FALSE,
1007                                                  Event,
1008                                                  &IoStatusBlock);
1009         if (!Irp)
1010         {
1011             /* Fail, free the event */
1012             ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
1013             return STATUS_INSUFFICIENT_RESOURCES;
1014         }
1015 
1016         /* Reset event */
1017         KeClearEvent(Event);
1018 
1019         /* Call the driver and check if it's pending */
1020         Status = IoCallDriver(DeviceObject, Irp);
1021         if (Status == STATUS_PENDING)
1022         {
1023             /* Wait on the driver */
1024             KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
1025             Status = IoStatusBlock.Status;
1026         }
1027 
1028         /* Check if the driver returned success */
1029         if(NT_SUCCESS(Status))
1030         {
1031             /* Get the number of sectors */
1032             *RealSectorCount = (PartitionInfo.PartitionLength.QuadPart /
1033                                 Geometry->BytesPerSector);
1034         }
1035     }
1036 
1037     /* Free the event and return the Status */
1038     ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
1039     return Status;
1040 }
1041 
1042 BOOLEAN
1043 NTAPI
1044 HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry,
1045                           IN ULONGLONG MaxOffset,
1046                           IN ULONGLONG MaxSector)
1047 {
1048     ULONGLONG EndingSector;
1049     PAGED_CODE();
1050 
1051     /* Unused partitions are considered valid */
1052     if (Entry->PartitionType == PARTITION_ENTRY_UNUSED) return TRUE;
1053 
1054     /* Get the last sector of the partition */
1055     EndingSector = GET_STARTING_SECTOR(Entry) +  GET_PARTITION_LENGTH(Entry);
1056 
1057     /* Check if it's more then the maximum sector */
1058     if (EndingSector > MaxSector)
1059     {
1060         /* Invalid partition */
1061         DPRINT1("FSTUB: entry is invalid\n");
1062         DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
1063         DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
1064         DPRINT1("FSTUB: end %#I64x\n", EndingSector);
1065         DPRINT1("FSTUB: max %#I64x\n", MaxSector);
1066         return FALSE;
1067     }
1068     else if(GET_STARTING_SECTOR(Entry) > MaxOffset)
1069     {
1070         /* Invalid partition */
1071         DPRINT1("FSTUB: entry is invalid\n");
1072         DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
1073         DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
1074         DPRINT1("FSTUB: end %#I64x\n", EndingSector);
1075         DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset);
1076         return FALSE;
1077     }
1078 
1079     /* It's fine, return success */
1080     return TRUE;
1081 }
1082 
1083 VOID
1084 NTAPI
1085 HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset,
1086                        IN PLARGE_INTEGER PartitionLength,
1087                        IN CCHAR ShiftCount,
1088                        IN ULONG SectorsPerTrack,
1089                        IN ULONG NumberOfTracks,
1090                        IN ULONG ConventionalCylinders,
1091                        OUT PPARTITION_DESCRIPTOR PartitionDescriptor)
1092 {
1093     LARGE_INTEGER FirstSector, SectorCount;
1094     ULONG LastSector, Remainder, SectorsPerCylinder;
1095     ULONG StartingCylinder, EndingCylinder;
1096     ULONG StartingTrack, EndingTrack;
1097     ULONG StartingSector, EndingSector;
1098     PAGED_CODE();
1099 
1100     /* Calculate the number of sectors for each cylinder */
1101     SectorsPerCylinder = SectorsPerTrack * NumberOfTracks;
1102 
1103     /* Calculate the first sector, and the sector count */
1104     FirstSector.QuadPart = PartitionOffset->QuadPart >> ShiftCount;
1105     SectorCount.QuadPart = PartitionLength->QuadPart >> ShiftCount;
1106 
1107     /* Now calculate the last sector */
1108     LastSector = FirstSector.LowPart + SectorCount.LowPart - 1;
1109 
1110     /* Calculate the first and last cylinders */
1111     StartingCylinder = FirstSector.LowPart / SectorsPerCylinder;
1112     EndingCylinder = LastSector / SectorsPerCylinder;
1113 
1114     /* Set the default number of cylinders */
1115     if (!ConventionalCylinders) ConventionalCylinders = 1024;
1116 
1117     /* Normalize the values */
1118     if (StartingCylinder >= ConventionalCylinders)
1119     {
1120         /* Set the maximum to 1023 */
1121         StartingCylinder = ConventionalCylinders - 1;
1122     }
1123     if (EndingCylinder >= ConventionalCylinders)
1124     {
1125         /* Set the maximum to 1023 */
1126         EndingCylinder = ConventionalCylinders - 1;
1127     }
1128 
1129     /* Calculate the starting head and sector that still remain */
1130     Remainder = FirstSector.LowPart % SectorsPerCylinder;
1131     StartingTrack = Remainder / SectorsPerTrack;
1132     StartingSector = Remainder % SectorsPerTrack;
1133 
1134     /* Calculate the ending head and sector that still remain */
1135     Remainder = LastSector % SectorsPerCylinder;
1136     EndingTrack = Remainder / SectorsPerTrack;
1137     EndingSector = Remainder % SectorsPerTrack;
1138 
1139     /* Set cylinder data for the MSB */
1140     PartitionDescriptor->StartingCylinderMsb = (UCHAR)StartingCylinder;
1141     PartitionDescriptor->EndingCylinderMsb = (UCHAR)EndingCylinder;
1142 
1143     /* Set the track data */
1144     PartitionDescriptor->StartingTrack = (UCHAR)StartingTrack;
1145     PartitionDescriptor->EndingTrack = (UCHAR)EndingTrack;
1146 
1147     /* Update cylinder data for the LSB */
1148     StartingCylinder = ((StartingSector + 1) & 0x3F) |
1149                        ((StartingCylinder >> 2) & 0xC0);
1150     EndingCylinder = ((EndingSector + 1) & 0x3F) |
1151                      ((EndingCylinder >> 2) & 0xC0);
1152 
1153     /* Set the cylinder data for the LSB */
1154     PartitionDescriptor->StartingCylinderLsb = (UCHAR)StartingCylinder;
1155     PartitionDescriptor->EndingCylinderLsb = (UCHAR)EndingCylinder;
1156 }
1157 
1158 VOID
1159 FASTCALL
1160 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject,
1161                        IN PULONG ConventionalCylinders,
1162                        IN PLONGLONG DiskSize)
1163 {
1164     PDISK_GEOMETRY DiskGeometry = NULL;
1165     PIO_STATUS_BLOCK IoStatusBlock = NULL;
1166     PKEVENT Event = NULL;
1167     PIRP Irp;
1168     NTSTATUS Status;
1169 
1170     /* Set defaults */
1171     *ConventionalCylinders = 0;
1172     *DiskSize = 0;
1173 
1174     /* Allocate the structure in nonpaged pool */
1175     DiskGeometry = ExAllocatePoolWithTag(NonPagedPool,
1176                                          sizeof(DISK_GEOMETRY),
1177                                          TAG_FILE_SYSTEM);
1178     if (!DiskGeometry) goto Cleanup;
1179 
1180     /* Allocate the status block in nonpaged pool */
1181     IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool,
1182                                           sizeof(IO_STATUS_BLOCK),
1183                                           TAG_FILE_SYSTEM);
1184     if (!IoStatusBlock) goto Cleanup;
1185 
1186     /* Allocate the event in nonpaged pool too */
1187     Event = ExAllocatePoolWithTag(NonPagedPool,
1188                                   sizeof(KEVENT),
1189                                   TAG_FILE_SYSTEM);
1190     if (!Event) goto Cleanup;
1191 
1192     /* Initialize the event */
1193     KeInitializeEvent(Event, NotificationEvent, FALSE);
1194 
1195     /* Build the IRP */
1196     Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
1197                                         DeviceObject,
1198                                         NULL,
1199                                         0,
1200                                         DiskGeometry,
1201                                         sizeof(DISK_GEOMETRY),
1202                                         FALSE,
1203                                         Event,
1204                                         IoStatusBlock);
1205     if (!Irp) goto Cleanup;
1206 
1207     /* Now call the driver */
1208     Status = IoCallDriver(DeviceObject, Irp);
1209     if (Status == STATUS_PENDING)
1210     {
1211         /* Wait for it to complete */
1212         KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
1213         Status = IoStatusBlock->Status;
1214     }
1215 
1216     /* Check driver status */
1217     if (NT_SUCCESS(Status))
1218     {
1219         /* Return the cylinder count */
1220         *ConventionalCylinders = DiskGeometry->Cylinders.LowPart;
1221 
1222         /* Make sure it's not larger then 1024 */
1223         if (DiskGeometry->Cylinders.LowPart >= 1024)
1224         {
1225             /* Otherwise, normalize the value */
1226             *ConventionalCylinders = 1024;
1227         }
1228 
1229         /* Calculate the disk size */
1230         *DiskSize = DiskGeometry->Cylinders.QuadPart *
1231                     DiskGeometry->TracksPerCylinder *
1232                     DiskGeometry->SectorsPerTrack *
1233                     DiskGeometry->BytesPerSector;
1234     }
1235 
1236 Cleanup:
1237     /* Free all the pointers */
1238     if (Event) ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
1239     if (IoStatusBlock) ExFreePoolWithTag(IoStatusBlock, TAG_FILE_SYSTEM);
1240     if (DiskGeometry) ExFreePoolWithTag(DiskGeometry, TAG_FILE_SYSTEM);
1241     return;
1242 }
1243 
1244 VOID
1245 FASTCALL
1246 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
1247                IN ULONG SectorSize,
1248                IN ULONG MbrTypeIdentifier,
1249                OUT PVOID *MbrBuffer)
1250 {
1251     LARGE_INTEGER Offset;
1252     PUCHAR Buffer;
1253     ULONG BufferSize;
1254     KEVENT Event;
1255     IO_STATUS_BLOCK IoStatusBlock;
1256     PIRP Irp;
1257     PPARTITION_DESCRIPTOR PartitionDescriptor;
1258     NTSTATUS Status;
1259     PIO_STACK_LOCATION IoStackLocation;
1260     Offset.QuadPart = 0;
1261 
1262     /* Assume failure */
1263     *MbrBuffer = NULL;
1264 
1265     /* Normalize the buffer size */
1266     BufferSize = max(SectorSize, 512);
1267 
1268     /* Allocate the buffer */
1269     Buffer = ExAllocatePoolWithTag(NonPagedPool,
1270                                        PAGE_SIZE > BufferSize ?
1271                                        PAGE_SIZE : BufferSize,
1272                                        TAG_FILE_SYSTEM);
1273     if (!Buffer) return;
1274 
1275     /* Initialize the Event */
1276     KeInitializeEvent(&Event, NotificationEvent, FALSE);
1277 
1278     /* Build the IRP */
1279     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1280                                        DeviceObject,
1281                                        Buffer,
1282                                        BufferSize,
1283                                        &Offset,
1284                                        &Event,
1285                                        &IoStatusBlock);
1286     if (!Irp)
1287     {
1288         /* Failed */
1289         ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1290         return;
1291     }
1292 
1293     /* Make sure to override volume verification */
1294     IoStackLocation = IoGetNextIrpStackLocation(Irp);
1295     IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1296 
1297     /* Call the driver */
1298     Status = IoCallDriver(DeviceObject, Irp);
1299     if (Status == STATUS_PENDING)
1300     {
1301         /* Wait for completion */
1302         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1303         Status = IoStatusBlock.Status;
1304     }
1305 
1306     /* Check driver Status */
1307     if (NT_SUCCESS(Status))
1308     {
1309         /* Validate the MBR Signature */
1310         if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1311         {
1312             /* Failed */
1313             ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1314             return;
1315         }
1316 
1317         /* Get the partition entry */
1318         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1319                                &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1320 
1321         /* Make sure it's what the caller wanted */
1322         if (PartitionDescriptor->PartitionType != MbrTypeIdentifier)
1323         {
1324             /* It's not, free our buffer */
1325             ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1326         }
1327         else
1328         {
1329             /* Check if this is a secondary entry */
1330             if (PartitionDescriptor->PartitionType == 0x54)
1331             {
1332                 /* Return our buffer, but at sector 63 */
1333                 *(PULONG)Buffer = 63;
1334                 *MbrBuffer = Buffer;
1335             }
1336             else if (PartitionDescriptor->PartitionType == 0x55)
1337             {
1338                 /* EZ Drive, return the buffer directly */
1339                 *MbrBuffer = Buffer;
1340             }
1341             else
1342             {
1343                 /* Otherwise crash on debug builds */
1344                 ASSERT(PartitionDescriptor->PartitionType == 0x55);
1345             }
1346         }
1347     }
1348 }
1349 
1350 VOID
1351 NTAPI
1352 FstubFixupEfiPartition(IN PPARTITION_DESCRIPTOR PartitionDescriptor,
1353                        IN ULONGLONG MaxOffset)
1354 {
1355     ULONG PartitionMaxOffset, PartitionLength;
1356     PAGED_CODE();
1357 
1358     /* Compute partition length (according to MBR entry) */
1359     PartitionMaxOffset = GET_STARTING_SECTOR(PartitionDescriptor) + GET_PARTITION_LENGTH(PartitionDescriptor);
1360     /* In case the partition length goes beyond disk size... */
1361     if (PartitionMaxOffset > MaxOffset)
1362     {
1363         /* Resize partition to its maximum real length */
1364         PartitionLength = (ULONG)(PartitionMaxOffset - GET_STARTING_SECTOR(PartitionDescriptor));
1365         SET_PARTITION_LENGTH(PartitionDescriptor, PartitionLength);
1366     }
1367 }
1368 
1369 NTSTATUS
1370 FASTCALL
1371 xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
1372                          IN ULONG SectorSize,
1373                          IN BOOLEAN ReturnRecognizedPartitions,
1374                          IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
1375 {
1376     KEVENT Event;
1377     IO_STATUS_BLOCK IoStatusBlock;
1378     PIRP Irp;
1379     PPARTITION_DESCRIPTOR PartitionDescriptor;
1380     CCHAR Entry;
1381     NTSTATUS Status;
1382     PPARTITION_INFORMATION PartitionInfo;
1383     PUCHAR Buffer = NULL;
1384     ULONG BufferSize = 2048, InputSize;
1385     PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo = NULL;
1386     LONG j = -1, i = -1, k;
1387     DISK_GEOMETRY DiskGeometry;
1388     LONGLONG EndSector, MaxSector, StartOffset;
1389     ULONGLONG MaxOffset;
1390     LARGE_INTEGER Offset, VolumeOffset;
1391     BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE, MbrFound = FALSE;
1392     BOOLEAN IsValid, IsEmpty = TRUE;
1393     PVOID MbrBuffer;
1394     PIO_STACK_LOCATION IoStackLocation;
1395     PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer;
1396     UCHAR PartitionType;
1397     LARGE_INTEGER HiddenSectors64;
1398     VolumeOffset.QuadPart = Offset.QuadPart = 0;
1399     PAGED_CODE();
1400 
1401     /* Allocate the buffer */
1402     *PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
1403                                              BufferSize,
1404                                              TAG_FILE_SYSTEM);
1405     if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES;
1406 
1407     /* Normalize the buffer size */
1408     InputSize = max(512, SectorSize);
1409 
1410     /* Check for EZ Drive */
1411     HalExamineMBR(DeviceObject, InputSize, 0x55, &MbrBuffer);
1412     if (MbrBuffer)
1413     {
1414         /* EZ Drive found, bias the offset */
1415         IsEzDrive = TRUE;
1416         ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
1417         Offset.QuadPart = 512;
1418     }
1419 
1420     /* Get drive geometry */
1421     Status = HalpGetFullGeometry(DeviceObject, &DiskGeometry, &MaxOffset);
1422     if (!NT_SUCCESS(Status))
1423     {
1424         ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1425         *PartitionBuffer = NULL;
1426         return Status;
1427     }
1428 
1429     /* Get the end and maximum sector */
1430     EndSector = MaxOffset;
1431     MaxSector = MaxOffset << 1;
1432     DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n",
1433             MaxOffset, MaxSector);
1434 
1435     /* Allocate our buffer */
1436     Buffer = ExAllocatePoolWithTag(NonPagedPool, InputSize, TAG_FILE_SYSTEM);
1437     if (!Buffer)
1438     {
1439         /* Fail, free the input buffer */
1440         ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1441         *PartitionBuffer = NULL;
1442         return STATUS_INSUFFICIENT_RESOURCES;
1443     }
1444 
1445     /* Start partition loop */
1446     do
1447     {
1448         /* Assume the partition is valid */
1449         IsValid = TRUE;
1450 
1451         /* Initialize the event */
1452         KeInitializeEvent(&Event, NotificationEvent, FALSE);
1453 
1454         /* Clear the buffer and build the IRP */
1455         RtlZeroMemory(Buffer, InputSize);
1456         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1457                                            DeviceObject,
1458                                            Buffer,
1459                                            InputSize,
1460                                            &Offset,
1461                                            &Event,
1462                                            &IoStatusBlock);
1463         if (!Irp)
1464         {
1465             /* Failed */
1466             Status = STATUS_INSUFFICIENT_RESOURCES;
1467             break;
1468         }
1469 
1470         /* Make sure to disable volume verification */
1471         IoStackLocation = IoGetNextIrpStackLocation(Irp);
1472         IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1473 
1474         /* Call the driver */
1475         Status = IoCallDriver(DeviceObject, Irp);
1476         if (Status == STATUS_PENDING)
1477         {
1478             /* Wait for completion */
1479             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1480             Status = IoStatusBlock.Status;
1481         }
1482 
1483         /* Normalize status code and check for failure */
1484         if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS;
1485         if (!NT_SUCCESS(Status)) break;
1486 
1487         /* If we biased for EZ-Drive, unbias now */
1488         if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
1489 
1490         /* Make sure this is a valid MBR */
1491         if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1492         {
1493             /* It's not, fail */
1494             DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "
1495                     "partition table %d\n", j + 1);
1496             break;
1497         }
1498 
1499         /* At this point we have a valid MBR */
1500         MbrFound = TRUE;
1501 
1502         /* Check if we weren't given an offset */
1503         if (!Offset.QuadPart)
1504         {
1505             /* Then read the signature off the disk */
1506             (*PartitionBuffer)->Signature =  ((PULONG)Buffer)
1507                                              [PARTITION_TABLE_OFFSET / 2 - 1];
1508         }
1509 
1510         /* Get the partition descriptor array */
1511         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1512                                &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1513 
1514         /* Start looping partitions */
1515         j++;
1516         DPRINT("FSTUB: Partition Table %d:\n", j);
1517         for (Entry = 1, k = 0; Entry <= 4; Entry++, PartitionDescriptor++)
1518         {
1519             /* Get the partition type */
1520             PartitionType = PartitionDescriptor->PartitionType;
1521 
1522             /* Print debug messages */
1523             DPRINT("Partition Entry %d,%d: type %#x %s\n",
1524                     j,
1525                     Entry,
1526                     PartitionType,
1527                     (PartitionDescriptor->ActiveFlag) ? "Active" : "");
1528             DPRINT("\tOffset %#08lx for %#08lx Sectors\n",
1529                     GET_STARTING_SECTOR(PartitionDescriptor),
1530                     GET_PARTITION_LENGTH(PartitionDescriptor));
1531 
1532             /* Check whether we're facing a protective MBR */
1533             if (PartitionType == EFI_PMBR_OSTYPE_EFI)
1534             {
1535                 /* Partition length might be bigger than disk size */
1536                 FstubFixupEfiPartition(PartitionDescriptor,
1537                                        MaxOffset);
1538             }
1539 
1540             /* Make sure that the partition is valid, unless it's the first */
1541             if (!(HalpIsValidPartitionEntry(PartitionDescriptor,
1542                                             MaxOffset,
1543                                             MaxSector)) && !(j))
1544             {
1545                 /* It's invalid, so fail */
1546                 IsValid = FALSE;
1547                 break;
1548             }
1549 
1550             /* Check if it's a container */
1551             if (IsContainerPartition(PartitionType))
1552             {
1553                 /* Increase the count of containers */
1554                 if (++k != 1)
1555                 {
1556                     /* More then one table is invalid */
1557                     DPRINT1("FSTUB: Multiple container partitions found in "
1558                             "partition table %d\n - table is invalid\n",
1559                             j);
1560                     IsValid = FALSE;
1561                     break;
1562                 }
1563             }
1564 
1565             /* Check if the partition is supposedly empty */
1566             if (IsEmpty)
1567             {
1568                 /* But check if it actually has a start and/or length */
1569                 if ((GET_STARTING_SECTOR(PartitionDescriptor)) ||
1570                     (GET_PARTITION_LENGTH(PartitionDescriptor)))
1571                 {
1572                     /* So then it's not really empty */
1573                     IsEmpty = FALSE;
1574                 }
1575             }
1576 
1577             /* Check if the caller wanted only recognized partitions */
1578             if (ReturnRecognizedPartitions)
1579             {
1580                 /* Then check if this one is unused, or a container */
1581                 if ((PartitionType == PARTITION_ENTRY_UNUSED) ||
1582                     IsContainerPartition(PartitionType))
1583                 {
1584                     /* Skip it, since the caller doesn't want it */
1585                     continue;
1586                 }
1587             }
1588 
1589             /* Increase the structure count and check if they can fit */
1590             if ((sizeof(DRIVE_LAYOUT_INFORMATION) +
1591                  (++i * sizeof(PARTITION_INFORMATION))) >
1592                 BufferSize)
1593             {
1594                 /* Allocate a new buffer that's twice as big */
1595                 DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool,
1596                                                         BufferSize << 1,
1597                                                         TAG_FILE_SYSTEM);
1598                 if (!DriveLayoutInfo)
1599                 {
1600                     /* Out of memory, unto this extra structure */
1601                     --i;
1602                     Status = STATUS_INSUFFICIENT_RESOURCES;
1603                     break;
1604                 }
1605 
1606                 /* Copy the contents of the old buffer */
1607                 RtlMoveMemory(DriveLayoutInfo,
1608                               *PartitionBuffer,
1609                               BufferSize);
1610 
1611                 /* Free the old buffer and set this one as the new one */
1612                 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1613                 *PartitionBuffer = DriveLayoutInfo;
1614 
1615                 /* Double the size */
1616                 BufferSize <<= 1;
1617             }
1618 
1619             /* Now get the current structure being filled and initialize it */
1620             PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i];
1621             PartitionInfo->PartitionType = PartitionType;
1622             PartitionInfo->RewritePartition = FALSE;
1623 
1624             /* Check if we're dealing with a partition that's in use */
1625             if (PartitionType != PARTITION_ENTRY_UNUSED)
1626             {
1627                 /* Check if it's bootable */
1628                 PartitionInfo->BootIndicator = PartitionDescriptor->
1629                                                ActiveFlag & 0x80 ?
1630                                                TRUE : FALSE;
1631 
1632                 /* Check if its' a container */
1633                 if (IsContainerPartition(PartitionType))
1634                 {
1635                     /* Then don't recognize it and use the volume offset */
1636                     PartitionInfo->RecognizedPartition = FALSE;
1637                     StartOffset = VolumeOffset.QuadPart;
1638                 }
1639                 else
1640                 {
1641                     /* Then recognize it and use the partition offset */
1642                     PartitionInfo->RecognizedPartition = TRUE;
1643                     StartOffset = Offset.QuadPart;
1644                 }
1645 
1646                 /* Get the starting offset */
1647                 PartitionInfo->StartingOffset.QuadPart =
1648                     StartOffset +
1649                     UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor),
1650                                   SectorSize);
1651 
1652                 /* Calculate the number of hidden sectors */
1653                 HiddenSectors64.QuadPart = (PartitionInfo->
1654                                             StartingOffset.QuadPart -
1655                                             StartOffset) /
1656                                             SectorSize;
1657                 PartitionInfo->HiddenSectors = HiddenSectors64.LowPart;
1658 
1659                 /* Get the partition length */
1660                 PartitionInfo->PartitionLength.QuadPart =
1661                     UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor),
1662                                   SectorSize);
1663 
1664                 /* Get the partition number */
1665                 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartitionType)) ? i + 1 : 0;
1666             }
1667             else
1668             {
1669                 /* Otherwise, clear all the relevant fields */
1670                 PartitionInfo->BootIndicator = FALSE;
1671                 PartitionInfo->RecognizedPartition = FALSE;
1672                 PartitionInfo->StartingOffset.QuadPart = 0;
1673                 PartitionInfo->PartitionLength.QuadPart = 0;
1674                 PartitionInfo->HiddenSectors = 0;
1675 
1676                 PartitionInfo->PartitionNumber = 0;
1677             }
1678         }
1679 
1680         /* Finish debug log, and check for failure */
1681         DPRINT("\n");
1682         if (!NT_SUCCESS(Status)) break;
1683 
1684         /* Also check if we hit an invalid entry here */
1685         if (!IsValid)
1686         {
1687             /* We did, so break out of the loop minus one entry */
1688             j--;
1689             break;
1690         }
1691 
1692         /* Reset the offset */
1693         Offset.QuadPart = 0;
1694 
1695         /* Go back to the descriptor array and loop it */
1696         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1697                                &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1698         for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
1699         {
1700             /* Check if this is a container partition, since we skipped them */
1701             if (IsContainerPartition(PartitionDescriptor->PartitionType))
1702             {
1703                 /* Get its offset */
1704                 Offset.QuadPart = VolumeOffset.QuadPart +
1705                                   UInt32x32To64(
1706                                      GET_STARTING_SECTOR(PartitionDescriptor),
1707                                      SectorSize);
1708 
1709                 /* If this is a primary partition, this is the volume offset */
1710                 if (IsPrimary) VolumeOffset = Offset;
1711 
1712                 /* Also update the maximum sector */
1713                 MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor);
1714                 DPRINT1("FSTUB: MaxSector now = %I64d\n", MaxSector);
1715                 break;
1716             }
1717         }
1718 
1719         /* Loop the next partitions, which are not primary anymore */
1720         IsPrimary = FALSE;
1721     } while (Offset.HighPart | Offset.LowPart);
1722 
1723     /* Check if this is a removable device that's probably a super-floppy */
1724     if ((DiskGeometry.MediaType == RemovableMedia) &&
1725         !(j) &&
1726         (MbrFound) &&
1727         (IsEmpty))
1728     {
1729         /* Read the jump bytes to detect super-floppy */
1730         if ((BootSectorInfo->JumpByte[0] == 0xeb) ||
1731             (BootSectorInfo->JumpByte[0] == 0xe9))
1732         {
1733             /* Super floppes don't have typical MBRs, so skip them */
1734             DPRINT1("FSTUB: Jump byte %#x found along with empty partition "
1735                     "table - disk is a super floppy and has no valid MBR\n",
1736                     BootSectorInfo->JumpByte);
1737             j = -1;
1738         }
1739     }
1740 
1741     /* Check if we're still at partition -1 */
1742     if (j == -1)
1743     {
1744         /* The likely cause is the super floppy detection above */
1745         if ((MbrFound) || (DiskGeometry.MediaType == RemovableMedia))
1746         {
1747             /* Print out debugging information */
1748             DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "
1749                     "super-floppy\n",
1750                     DeviceObject);
1751             DPRINT1("FSTUB: Drive has %I64d sectors and is %#016I64x "
1752                     "bytes large\n",
1753                     EndSector, EndSector * DiskGeometry.BytesPerSector);
1754 
1755             /* We should at least have some sectors */
1756             if (EndSector > 0)
1757             {
1758                 /* Get the entry we'll use */
1759                 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0];
1760 
1761                 /* Fill it out with data for a super-floppy */
1762                 PartitionInfo->RewritePartition = FALSE;
1763                 PartitionInfo->RecognizedPartition = TRUE;
1764                 PartitionInfo->PartitionType = PARTITION_FAT_16;
1765                 PartitionInfo->BootIndicator = FALSE;
1766                 PartitionInfo->HiddenSectors = 0;
1767                 PartitionInfo->StartingOffset.QuadPart = 0;
1768                 PartitionInfo->PartitionLength.QuadPart = (EndSector *
1769                                                            DiskGeometry.
1770                                                            BytesPerSector);
1771 
1772                 /* FIXME: REACTOS HACK */
1773                 PartitionInfo->PartitionNumber = 0;
1774 
1775                 /* Set the signature and set the count back to 0 */
1776                 (*PartitionBuffer)->Signature = 1;
1777                 i = 0;
1778             }
1779         }
1780         else
1781         {
1782             /* Otherwise, this isn't a super floppy, so set an invalid count */
1783             i = -1;
1784         }
1785     }
1786 
1787     /* Set the partition count */
1788     (*PartitionBuffer)->PartitionCount = ++i;
1789 
1790     /* If we have no count, delete the signature */
1791     if (!i) (*PartitionBuffer)->Signature = 0;
1792 
1793     /* Free the buffer and check for success */
1794     if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1795     if (!NT_SUCCESS(Status))
1796     {
1797         ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1798         *PartitionBuffer = NULL;
1799     }
1800 
1801     /* Return status */
1802     return Status;
1803 }
1804 
1805 NTSTATUS
1806 FASTCALL
1807 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
1808                               IN ULONG SectorSize,
1809                               IN ULONG PartitionNumber,
1810                               IN ULONG PartitionType)
1811 {
1812     PIRP Irp;
1813     KEVENT Event;
1814     IO_STATUS_BLOCK IoStatusBlock;
1815     NTSTATUS Status;
1816     LARGE_INTEGER Offset, VolumeOffset;
1817     PUCHAR Buffer = NULL;
1818     ULONG BufferSize;
1819     ULONG i = 0;
1820     ULONG Entry;
1821     PPARTITION_DESCRIPTOR PartitionDescriptor;
1822     BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE;
1823     PVOID MbrBuffer;
1824     PIO_STACK_LOCATION IoStackLocation;
1825     VolumeOffset.QuadPart = Offset.QuadPart = 0;
1826     PAGED_CODE();
1827 
1828     /* Normalize the buffer size */
1829     BufferSize = max(512, SectorSize);
1830 
1831     /* Check for EZ Drive */
1832     HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer);
1833     if (MbrBuffer)
1834     {
1835         /* EZ Drive found, bias the offset */
1836         IsEzDrive = TRUE;
1837         ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
1838         Offset.QuadPart = 512;
1839     }
1840 
1841     /* Allocate our partition buffer */
1842     Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
1843     if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1844 
1845     /* Initialize the event we'll use and loop partitions */
1846     KeInitializeEvent(&Event, NotificationEvent, FALSE);
1847     do
1848     {
1849         /* Reset the event since we reuse it */
1850         KeClearEvent(&Event);
1851 
1852         /* Build the read IRP */
1853         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1854                                            DeviceObject,
1855                                            Buffer,
1856                                            BufferSize,
1857                                            &Offset,
1858                                            &Event,
1859                                            &IoStatusBlock);
1860         if (!Irp)
1861         {
1862             /* Fail */
1863             Status = STATUS_INSUFFICIENT_RESOURCES;
1864             break;
1865         }
1866 
1867         /* Make sure to disable volume verification */
1868         IoStackLocation = IoGetNextIrpStackLocation(Irp);
1869         IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1870 
1871         /* Call the driver */
1872         Status = IoCallDriver(DeviceObject, Irp);
1873         if (Status == STATUS_PENDING)
1874         {
1875             /* Wait for completion */
1876             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1877             Status = IoStatusBlock.Status;
1878         }
1879 
1880         /* Check for failure */
1881         if (!NT_SUCCESS(Status)) break;
1882 
1883         /* If we biased for EZ-Drive, unbias now */
1884         if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
1885 
1886         /* Make sure this is a valid MBR */
1887         if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1888         {
1889             /* It's not, fail */
1890             Status = STATUS_BAD_MASTER_BOOT_RECORD;
1891             break;
1892         }
1893 
1894         /* Get the partition descriptors and loop them */
1895         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1896                               &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1897         for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
1898         {
1899             /* Check if it's unused or a container partition */
1900             if ((PartitionDescriptor->PartitionType ==
1901                  PARTITION_ENTRY_UNUSED) ||
1902                 (IsContainerPartition(PartitionDescriptor->PartitionType)))
1903             {
1904                 /* Go to the next one */
1905                 continue;
1906             }
1907 
1908             /* It's a valid partition, so increase the partition count */
1909             if (++i == PartitionNumber)
1910             {
1911                 /* We found a match, set the type */
1912                 PartitionDescriptor->PartitionType = (UCHAR)PartitionType;
1913 
1914                 /* Reset the reusable event */
1915                 KeClearEvent(&Event);
1916 
1917                 /* Build the write IRP */
1918                 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
1919                                                    DeviceObject,
1920                                                    Buffer,
1921                                                    BufferSize,
1922                                                    &Offset,
1923                                                    &Event,
1924                                                    &IoStatusBlock);
1925                 if (!Irp)
1926                 {
1927                     /* Fail */
1928                     Status = STATUS_INSUFFICIENT_RESOURCES;
1929                     break;
1930                 }
1931 
1932                 /* Disable volume verification */
1933                 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1934                 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1935 
1936                 /* Call the driver */
1937                 Status = IoCallDriver(DeviceObject, Irp);
1938                 if (Status == STATUS_PENDING)
1939                 {
1940                     /* Wait for completion */
1941                     KeWaitForSingleObject(&Event,
1942                                           Executive,
1943                                           KernelMode,
1944                                           FALSE,
1945                                           NULL);
1946                     Status = IoStatusBlock.Status;
1947                 }
1948 
1949                 /* We're done, break out of the loop */
1950                 break;
1951             }
1952         }
1953 
1954         /* If we looped all the partitions, break out */
1955         if (Entry <= NUM_PARTITION_TABLE_ENTRIES) break;
1956 
1957         /* Nothing found yet, get the partition array again */
1958         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1959                                &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1960         for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
1961         {
1962             /* Check if this was a container partition (we skipped these) */
1963             if (IsContainerPartition(PartitionDescriptor->PartitionType))
1964             {
1965                 /* Update the partition offset */
1966                 Offset.QuadPart = VolumeOffset.QuadPart +
1967                                   GET_STARTING_SECTOR(PartitionDescriptor) *
1968                                   SectorSize;
1969 
1970                 /* If this was the primary partition, update the volume too */
1971                 if (IsPrimary) VolumeOffset = Offset;
1972                 break;
1973             }
1974         }
1975 
1976         /* Check if we already searched all the partitions */
1977         if (Entry > NUM_PARTITION_TABLE_ENTRIES)
1978         {
1979             /* Then we failed to find a good MBR */
1980             Status = STATUS_BAD_MASTER_BOOT_RECORD;
1981             break;
1982         }
1983 
1984         /* Loop the next partitions, which are not primary anymore */
1985         IsPrimary = FALSE;
1986     } while (i < PartitionNumber);
1987 
1988     /* Everything done, cleanup */
1989     if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1990     return Status;
1991 }
1992 
1993 NTSTATUS
1994 FASTCALL
1995 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
1996                           IN ULONG SectorSize,
1997                           IN ULONG SectorsPerTrack,
1998                           IN ULONG NumberOfHeads,
1999                           IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
2000 {
2001     KEVENT Event;
2002     IO_STATUS_BLOCK IoStatusBlock;
2003     PIRP Irp;
2004     NTSTATUS Status = STATUS_SUCCESS;
2005     ULONG BufferSize;
2006     PUSHORT Buffer;
2007     PPTE Entry;
2008     PPARTITION_TABLE PartitionTable;
2009     LARGE_INTEGER Offset, NextOffset, ExtendedOffset, SectorOffset;
2010     LARGE_INTEGER StartOffset, PartitionLength;
2011     ULONG i, j;
2012     CCHAR k;
2013     BOOLEAN IsEzDrive = FALSE, IsSuperFloppy = FALSE, DoRewrite = FALSE, IsMbr;
2014     ULONG ConventionalCylinders;
2015     LONGLONG DiskSize;
2016     PDISK_LAYOUT DiskLayout = (PDISK_LAYOUT)PartitionBuffer;
2017     PVOID MbrBuffer;
2018     UCHAR PartitionType;
2019     PIO_STACK_LOCATION IoStackLocation;
2020     PPARTITION_INFORMATION PartitionInfo = PartitionBuffer->PartitionEntry;
2021     PPARTITION_INFORMATION TableEntry;
2022     ExtendedOffset.QuadPart = NextOffset.QuadPart = Offset.QuadPart = 0;
2023     PAGED_CODE();
2024 
2025     /* Normalize the buffer size */
2026     BufferSize = max(512, SectorSize);
2027 
2028     /* Get the partial drive geometry */
2029     xHalGetPartialGeometry(DeviceObject, &ConventionalCylinders, &DiskSize);
2030 
2031     /* Check for EZ Drive */
2032     HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer);
2033     if (MbrBuffer)
2034     {
2035         /* EZ Drive found, bias the offset */
2036         IsEzDrive = TRUE;
2037         ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
2038         Offset.QuadPart = 512;
2039     }
2040 
2041     /* Get the number of bits to shift to multiply by the sector size */
2042     for (k = 0; k < 32; k++) if ((SectorSize >> k) == 1) break;
2043 
2044     /* Check if there's only one partition */
2045     if (PartitionBuffer->PartitionCount == 1)
2046     {
2047         /* Check if it has no starting offset or hidden sectors */
2048         if (!(PartitionInfo->StartingOffset.QuadPart) &&
2049             !(PartitionInfo->HiddenSectors))
2050         {
2051             /* Then it's a super floppy */
2052             IsSuperFloppy = TRUE;
2053 
2054             /* Which also means it must be non-bootable FAT-16 */
2055             if ((PartitionInfo->PartitionNumber) ||
2056                 (PartitionInfo->PartitionType != PARTITION_FAT_16) ||
2057                 (PartitionInfo->BootIndicator))
2058             {
2059                 /* It's not, so we fail */
2060                 return STATUS_INVALID_PARAMETER;
2061             }
2062 
2063             /* Check if it needs a rewrite, and disable EZ drive for sure */
2064             if (PartitionInfo->RewritePartition) DoRewrite = TRUE;
2065             IsEzDrive = FALSE;
2066         }
2067     }
2068 
2069     /* Count the number of partition tables */
2070     DiskLayout->TableCount = (PartitionBuffer->PartitionCount + 4 - 1) / 4;
2071 
2072     /* Allocate our partition buffer */
2073     Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
2074     if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
2075 
2076     /* Loop the entries */
2077     Entry = (PPTE)&Buffer[PARTITION_TABLE_OFFSET];
2078     for (i = 0; i < DiskLayout->TableCount; i++)
2079     {
2080         /* Set if this is the MBR partition */
2081         IsMbr= (BOOLEAN)!i;
2082 
2083         /* Initialize th event */
2084         KeInitializeEvent(&Event, NotificationEvent, FALSE);
2085 
2086         /* Build the read IRP */
2087         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
2088                                            DeviceObject,
2089                                            Buffer,
2090                                            BufferSize,
2091                                            &Offset,
2092                                            &Event,
2093                                            &IoStatusBlock);
2094         if (!Irp)
2095         {
2096             /* Fail */
2097             Status = STATUS_INSUFFICIENT_RESOURCES;
2098             break;
2099         }
2100 
2101         /* Make sure to disable volume verification */
2102         IoStackLocation = IoGetNextIrpStackLocation(Irp);
2103         IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2104 
2105         /* Call the driver */
2106         Status = IoCallDriver(DeviceObject, Irp);
2107         if (Status == STATUS_PENDING)
2108         {
2109             /* Wait for completion */
2110             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
2111             Status = IoStatusBlock.Status;
2112         }
2113 
2114         /* Check for failure */
2115         if (!NT_SUCCESS(Status)) break;
2116 
2117         /* If we biased for EZ-Drive, unbias now */
2118         if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
2119 
2120         /* Check if this is a normal disk */
2121         if (!IsSuperFloppy)
2122         {
2123             /* Set the boot record signature */
2124             Buffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE;
2125 
2126             /* By default, don't require a rewrite */
2127             DoRewrite = FALSE;
2128 
2129             /* Check if we don't have an offset */
2130             if (!Offset.QuadPart)
2131             {
2132                 /* Check if the signature doesn't match */
2133                 if (((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] !=
2134                     PartitionBuffer->Signature)
2135                 {
2136                     /* Then write the signature and now w need a rewrite */
2137                     ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] =
2138                         PartitionBuffer->Signature;
2139                     DoRewrite = TRUE;
2140                 }
2141             }
2142 
2143             /* Loop the partition table entries */
2144             PartitionTable = &DiskLayout->PartitionTable[i];
2145             for (j = 0; j < 4; j++)
2146             {
2147                 /* Get the current entry and type */
2148                 TableEntry = &PartitionTable->PartitionEntry[j];
2149                 PartitionType = TableEntry->PartitionType;
2150 
2151                 /* Check if the entry needs a rewrite */
2152                 if (TableEntry->RewritePartition)
2153                 {
2154                     /* Then we need one too */
2155                     DoRewrite = TRUE;
2156 
2157                     /* Save the type and if it's a bootable partition */
2158                     Entry[j].PartitionType = TableEntry->PartitionType;
2159                     Entry[j].ActiveFlag = TableEntry->BootIndicator ? 0x80 : 0;
2160 
2161                     /* Make sure it's used */
2162                     if (PartitionType != PARTITION_ENTRY_UNUSED)
2163                     {
2164                         /* Make sure it's not a container (unless primary) */
2165                         if ((IsMbr) || !(IsContainerPartition(PartitionType)))
2166                         {
2167                             /* Use the partition offset */
2168                             StartOffset.QuadPart = Offset.QuadPart;
2169                         }
2170                         else
2171                         {
2172                             /* Use the extended logical partition offset */
2173                             StartOffset.QuadPart = ExtendedOffset.QuadPart;
2174                         }
2175 
2176                         /* Set the sector offset */
2177                         SectorOffset.QuadPart = TableEntry->
2178                                                 StartingOffset.QuadPart -
2179                                                 StartOffset.QuadPart;
2180 
2181                         /* Now calculate the starting sector */
2182                         StartOffset.QuadPart = SectorOffset.QuadPart >> k;
2183                         Entry[j].StartingSector = StartOffset.LowPart;
2184 
2185                         /* As well as the length */
2186                         PartitionLength.QuadPart = TableEntry->PartitionLength.
2187                                                    QuadPart >> k;
2188                         Entry[j].PartitionLength = PartitionLength.LowPart;
2189 
2190                         /* Calculate the CHS values */
2191                         HalpCalculateChsValues(&TableEntry->StartingOffset,
2192                                                &TableEntry->PartitionLength,
2193                                                k,
2194                                                SectorsPerTrack,
2195                                                NumberOfHeads,
2196                                                ConventionalCylinders,
2197                                                (PPARTITION_DESCRIPTOR)
2198                                                &Entry[j]);
2199                     }
2200                     else
2201                     {
2202                         /* Otherwise set up an empty entry */
2203                         Entry[j].StartingSector = 0;
2204                         Entry[j].PartitionLength = 0;
2205                         Entry[j].StartingTrack = 0;
2206                         Entry[j].EndingTrack = 0;
2207                         Entry[j].StartingCylinder = 0;
2208                         Entry[j].EndingCylinder = 0;
2209                     }
2210                 }
2211 
2212                 /* Check if this is a container partition */
2213                 if (IsContainerPartition(PartitionType))
2214                 {
2215                     /* Then update the offset to use */
2216                     NextOffset = TableEntry->StartingOffset;
2217                 }
2218             }
2219         }
2220 
2221         /* Check if we need to write back the buffer */
2222         if (DoRewrite)
2223         {
2224             /* We don't need to do this again */
2225             DoRewrite = FALSE;
2226 
2227             /* Initialize the event */
2228             KeInitializeEvent(&Event, NotificationEvent, FALSE);
2229 
2230             /* If we unbiased for EZ-Drive, rebias now */
2231             if ((IsEzDrive) && !(Offset.QuadPart)) Offset.QuadPart = 512;
2232 
2233             /* Build the write IRP */
2234             Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
2235                                                DeviceObject,
2236                                                Buffer,
2237                                                BufferSize,
2238                                                &Offset,
2239                                                &Event,
2240                                                &IoStatusBlock);
2241             if (!Irp)
2242             {
2243                 /* Fail */
2244                 Status = STATUS_INSUFFICIENT_RESOURCES;
2245                 break;
2246             }
2247 
2248             /* Make sure to disable volume verification */
2249             IoStackLocation = IoGetNextIrpStackLocation(Irp);
2250             IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2251 
2252             /* Call the driver */
2253             Status = IoCallDriver(DeviceObject, Irp);
2254             if (Status == STATUS_PENDING)
2255             {
2256                 /* Wait for completion */
2257                 KeWaitForSingleObject(&Event,
2258                                       Executive,
2259                                       KernelMode,
2260                                       FALSE,
2261                                       NULL);
2262                 Status = IoStatusBlock.Status;
2263             }
2264 
2265             /* Check for failure */
2266             if (!NT_SUCCESS(Status)) break;
2267 
2268             /* If we biased for EZ-Drive, unbias now */
2269             if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
2270         }
2271 
2272         /* Update the partition offset and set the extended offset if needed */
2273         Offset = NextOffset;
2274         if (IsMbr) ExtendedOffset = NextOffset;
2275     }
2276 
2277     /* If we had a buffer, free it, then return status */
2278     if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
2279     return Status;
2280 }
2281 
2282 /* PUBLIC FUNCTIONS **********************************************************/
2283 
2284 /*
2285  * @implemented
2286  */
2287 VOID
2288 FASTCALL
2289 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
2290               IN ULONG SectorSize,
2291               IN ULONG MbrTypeIdentifier,
2292               OUT PVOID *MbrBuffer)
2293 {
2294     HALDISPATCH->HalExamineMBR(DeviceObject,
2295                                SectorSize,
2296                                MbrTypeIdentifier,
2297                                MbrBuffer);
2298 }
2299 
2300 /*
2301  * @implemented
2302  */
2303 NTSTATUS
2304 FASTCALL
2305 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
2306                      IN ULONG SectorSize,
2307                      IN BOOLEAN ReturnRecognizedPartitions,
2308                      IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
2309 {
2310     return HALDISPATCH->HalIoReadPartitionTable(DeviceObject,
2311                                                 SectorSize,
2312                                                 ReturnRecognizedPartitions,
2313                                                 PartitionBuffer);
2314 }
2315 
2316 /*
2317  * @implemented
2318  */
2319 NTSTATUS
2320 FASTCALL
2321 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
2322                           IN ULONG SectorSize,
2323                           IN ULONG PartitionNumber,
2324                           IN ULONG PartitionType)
2325 {
2326     return HALDISPATCH->HalIoSetPartitionInformation(DeviceObject,
2327                                                      SectorSize,
2328                                                      PartitionNumber,
2329                                                      PartitionType);
2330 }
2331 
2332 /*
2333  * @implemented
2334  */
2335 NTSTATUS
2336 FASTCALL
2337 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
2338                       IN ULONG SectorSize,
2339                       IN ULONG SectorsPerTrack,
2340                       IN ULONG NumberOfHeads,
2341                       IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
2342 {
2343     return HALDISPATCH->HalIoWritePartitionTable(DeviceObject,
2344                                                  SectorSize,
2345                                                  SectorsPerTrack,
2346                                                  NumberOfHeads,
2347                                                  PartitionBuffer);
2348 }
2349 
2350 /*
2351  * @implemented
2352  */
2353 VOID
2354 FASTCALL
2355 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
2356                      IN PSTRING NtDeviceName,
2357                      OUT PUCHAR NtSystemPath,
2358                      OUT PSTRING NtSystemPathString)
2359 {
2360     HALDISPATCH->HalIoAssignDriveLetters(LoaderBlock,
2361                                          NtDeviceName,
2362                                          NtSystemPath,
2363                                          NtSystemPathString);
2364 }
2365 
2366 /* EOF */
2367