ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

disksup.c
Go to the documentation of this file.
00001 /*
00002 * PROJECT:         ReactOS Kernel
00003 * LICENSE:         GPL - See COPYING in the top level directory
00004 * FILE:            ntoskrnl/fstub/disksup.c
00005 * PURPOSE:         I/O HAL Routines for Disk Access
00006 * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007 *                  Eric Kohl
00008 *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
00009 */
00010 
00011 /* INCLUDES ******************************************************************/
00012 
00013 #include <ntoskrnl.h>
00014 #define NDEBUG
00015 #include <debug.h>
00016 #include <internal/hal.h>
00017 
00018 /* DEPRECATED FUNCTIONS ******************************************************/
00019 
00020 #if 1
00021 const WCHAR DiskMountString[] = L"\\DosDevices\\%C:";
00022 
00023 #define AUTO_DRIVE         MAXULONG
00024 
00025 #define PARTITION_MAGIC    0xaa55
00026 
00027 #define EFI_PMBR_OSTYPE_EFI 0xEE
00028 
00029 #include <pshpack1.h>
00030 
00031 typedef struct _REG_DISK_MOUNT_INFO
00032 {
00033     ULONG Signature;
00034     LARGE_INTEGER StartingOffset;
00035 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO;
00036 
00037 #include <poppack.h>
00038 
00039 typedef enum _DISK_MANAGER
00040 {
00041     NoDiskManager,
00042     OntrackDiskManager,
00043     EZ_Drive
00044 } DISK_MANAGER;
00045 
00046 static BOOLEAN
00047 HalpAssignDrive(IN PUNICODE_STRING PartitionName,
00048                 IN ULONG DriveNumber,
00049                 IN UCHAR DriveType,
00050                 IN ULONG Signature,
00051                 IN LARGE_INTEGER StartingOffset,
00052                 IN HANDLE hKey,
00053                 IN PUNICODE_STRING BootDevice,
00054                 OUT PUCHAR NtSystemPath)
00055 {
00056     WCHAR DriveNameBuffer[16];
00057     UNICODE_STRING DriveName;
00058     ULONG i;
00059     NTSTATUS Status;
00060     REG_DISK_MOUNT_INFO DiskMountInfo;
00061 
00062     DPRINT("HalpAssignDrive()\n");
00063 
00064     if ((DriveNumber != AUTO_DRIVE) && (DriveNumber < 26))
00065     {
00066         /* Force assignment */
00067         KeAcquireGuardedMutex(&ObpDeviceMapLock);
00068         if ((ObSystemDeviceMap->DriveMap & (1 << DriveNumber)) != 0)
00069         {
00070             DbgPrint("Drive letter already used!\n");
00071             KeReleaseGuardedMutex(&ObpDeviceMapLock);
00072             return FALSE;
00073         }
00074         KeReleaseGuardedMutex(&ObpDeviceMapLock);
00075     }
00076     else
00077     {
00078         /* Automatic assignment */
00079         DriveNumber = AUTO_DRIVE;
00080         KeAcquireGuardedMutex(&ObpDeviceMapLock);
00081         for (i = 2; i < 26; i++)
00082         {
00083             if ((ObSystemDeviceMap->DriveMap & (1 << i)) == 0)
00084             {
00085                 DriveNumber = i;
00086                 break;
00087             }
00088         }
00089         KeReleaseGuardedMutex(&ObpDeviceMapLock);
00090 
00091         if (DriveNumber == AUTO_DRIVE)
00092         {
00093             DbgPrint("No drive letter available!\n");
00094             return FALSE;
00095         }
00096     }
00097 
00098     DPRINT("DriveNumber %d\n", DriveNumber);
00099 
00100     /* Build drive name */
00101     swprintf(DriveNameBuffer,
00102         L"\\??\\%C:",
00103         'A' + DriveNumber);
00104     RtlInitUnicodeString(&DriveName,
00105         DriveNameBuffer);
00106 
00107     DPRINT("  %wZ ==> %wZ\n",
00108         &DriveName,
00109         PartitionName);
00110 
00111     /* Create symbolic link */
00112     Status = IoCreateSymbolicLink(&DriveName,
00113         PartitionName);
00114 
00115     if (hKey &&
00116         DriveType == DOSDEVICE_DRIVE_FIXED &&
00117         Signature)
00118     {
00119         DiskMountInfo.Signature = Signature;
00120         DiskMountInfo.StartingOffset = StartingOffset;
00121         swprintf(DriveNameBuffer, DiskMountString, L'A' + DriveNumber);
00122         RtlInitUnicodeString(&DriveName, DriveNameBuffer);
00123 
00124         Status = ZwSetValueKey(hKey,
00125             &DriveName,
00126             0,
00127             REG_BINARY,
00128             &DiskMountInfo,
00129             sizeof(DiskMountInfo));
00130         if (!NT_SUCCESS(Status))
00131         {
00132             DPRINT1("ZwCreateValueKey failed for %wZ, status=%x\n", &DriveName, Status);
00133         }
00134     }
00135 
00136     /* Check if this is a boot partition */
00137     if (RtlCompareUnicodeString(PartitionName, BootDevice, FALSE) == 0)
00138     {
00139         /* Set NtSystemPath to that partition's disk letter */
00140         *NtSystemPath = (UCHAR)('A' + DriveNumber);
00141     }
00142 
00143     return TRUE;
00144 }
00145 
00146 ULONG
00147 xHalpGetRDiskCount(VOID)
00148 {
00149     NTSTATUS Status;
00150     UNICODE_STRING ArcName;
00151     PWCHAR ArcNameBuffer;
00152     OBJECT_ATTRIBUTES ObjectAttributes;
00153     HANDLE DirectoryHandle;
00154     POBJECT_DIRECTORY_INFORMATION DirectoryInfo;
00155     ULONG Skip;
00156     ULONG ResultLength;
00157     ULONG CurrentRDisk;
00158     ULONG RDiskCount;
00159     BOOLEAN First = TRUE;
00160     ULONG Count;
00161 
00162     DirectoryInfo = ExAllocatePoolWithTag(PagedPool, 2 * PAGE_SIZE, TAG_FILE_SYSTEM);
00163     if (DirectoryInfo == NULL)
00164     {
00165         return 0;
00166     }
00167 
00168     RtlInitUnicodeString(&ArcName, L"\\ArcName");
00169     InitializeObjectAttributes(&ObjectAttributes,
00170         &ArcName,
00171         0,
00172         NULL,
00173         NULL);
00174 
00175     Status = ZwOpenDirectoryObject (&DirectoryHandle,
00176         SYMBOLIC_LINK_ALL_ACCESS,
00177         &ObjectAttributes);
00178     if (!NT_SUCCESS(Status))
00179     {
00180         DPRINT1("ZwOpenDirectoryObject for %wZ failed, status=%lx\n", &ArcName, Status);
00181         ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM);
00182         return 0;
00183     }
00184 
00185     RDiskCount = 0;
00186     Skip = 0;
00187     while (NT_SUCCESS(Status))
00188     {
00189         Status = NtQueryDirectoryObject (DirectoryHandle,
00190             DirectoryInfo,
00191             2 * PAGE_SIZE,
00192             FALSE,
00193             First,
00194             &Skip,
00195             &ResultLength);
00196         First = FALSE;
00197         if (NT_SUCCESS(Status))
00198         {
00199             Count = 0;
00200             while (DirectoryInfo[Count].Name.Buffer)
00201             {
00202                 DPRINT("Count %x\n", Count);
00203                 DirectoryInfo[Count].Name.Buffer[DirectoryInfo[Count].Name.Length / sizeof(WCHAR)] = 0;
00204                 ArcNameBuffer = DirectoryInfo[Count].Name.Buffer;
00205                 if (DirectoryInfo[Count].Name.Length >= sizeof(L"multi(0)disk(0)rdisk(0)") - sizeof(WCHAR) &&
00206                     !_wcsnicmp(ArcNameBuffer, L"multi(0)disk(0)rdisk(", (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR)))
00207                 {
00208                     DPRINT("%S\n", ArcNameBuffer);
00209                     ArcNameBuffer += (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR);
00210                     CurrentRDisk = 0;
00211                     while (iswdigit(*ArcNameBuffer))
00212                     {
00213                         CurrentRDisk = CurrentRDisk * 10 + *ArcNameBuffer - L'0';
00214                         ArcNameBuffer++;
00215                     }
00216                     if (!_wcsicmp(ArcNameBuffer, L")") &&
00217                         CurrentRDisk >= RDiskCount)
00218                     {
00219                         RDiskCount = CurrentRDisk + 1;
00220                     }
00221                 }
00222                 Count++;
00223             }
00224         }
00225     }
00226     ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM);
00227     return RDiskCount;
00228 }
00229 
00230 NTSTATUS
00231 xHalpGetDiskNumberFromRDisk(ULONG RDisk, PULONG DiskNumber)
00232 {
00233     WCHAR NameBuffer[80];
00234     UNICODE_STRING ArcName;
00235     UNICODE_STRING LinkName;
00236     OBJECT_ATTRIBUTES ObjectAttributes;
00237     HANDLE LinkHandle;
00238     NTSTATUS Status;
00239 
00240     swprintf(NameBuffer,
00241         L"\\ArcName\\multi(0)disk(0)rdisk(%lu)",
00242         RDisk);
00243 
00244     RtlInitUnicodeString(&ArcName, NameBuffer);
00245     InitializeObjectAttributes(&ObjectAttributes,
00246         &ArcName,
00247         0,
00248         NULL,
00249         NULL);
00250     Status = ZwOpenSymbolicLinkObject(&LinkHandle,
00251         SYMBOLIC_LINK_ALL_ACCESS,
00252         &ObjectAttributes);
00253     if (!NT_SUCCESS(Status))
00254     {
00255         DPRINT1("ZwOpenSymbolicLinkObject failed for %wZ, status=%lx\n", &ArcName, Status);
00256         return Status;
00257     }
00258 
00259     LinkName.Buffer = NameBuffer;
00260     LinkName.Length = 0;
00261     LinkName.MaximumLength = sizeof(NameBuffer);
00262     Status = ZwQuerySymbolicLinkObject(LinkHandle,
00263         &LinkName,
00264         NULL);
00265     ZwClose(LinkHandle);
00266     if (!NT_SUCCESS(Status))
00267     {
00268         DPRINT1("ZwQuerySymbolicLinkObject failed, status=%lx\n", Status);
00269         return Status;
00270     }
00271     if (LinkName.Length < sizeof(L"\\Device\\Harddisk0\\Partition0") - sizeof(WCHAR) ||
00272         LinkName.Length >= sizeof(NameBuffer))
00273     {
00274         return STATUS_UNSUCCESSFUL;
00275     }
00276 
00277     NameBuffer[LinkName.Length / sizeof(WCHAR)] = 0;
00278     if (_wcsnicmp(NameBuffer, L"\\Device\\Harddisk", (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR)))
00279     {
00280         return STATUS_UNSUCCESSFUL;
00281     }
00282     LinkName.Buffer += (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR);
00283 
00284     if (!iswdigit(*LinkName.Buffer))
00285     {
00286         return STATUS_UNSUCCESSFUL;
00287     }
00288     *DiskNumber = 0;
00289     while (iswdigit(*LinkName.Buffer))
00290     {
00291         *DiskNumber = *DiskNumber * 10 + *LinkName.Buffer - L'0';
00292         LinkName.Buffer++;
00293     }
00294     if (_wcsicmp(LinkName.Buffer, L"\\Partition0"))
00295     {
00296         return STATUS_UNSUCCESSFUL;
00297     }
00298     return STATUS_SUCCESS;
00299 }
00300 
00301 NTSTATUS
00302 FASTCALL
00303 xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName,
00304                      OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo)
00305 {
00306     IO_STATUS_BLOCK StatusBlock;
00307     DISK_GEOMETRY DiskGeometry;
00308     PDEVICE_OBJECT DeviceObject = NULL;
00309     PFILE_OBJECT FileObject;
00310     KEVENT Event;
00311     PIRP Irp;
00312     NTSTATUS Status;
00313 
00314     DPRINT("xHalpQueryDriveLayout %wZ %p\n",
00315         DeviceName,
00316         LayoutInfo);
00317 
00318     /* Get the drives sector size */
00319     Status = IoGetDeviceObjectPointer(DeviceName,
00320         FILE_READ_ATTRIBUTES,
00321         &FileObject,
00322         &DeviceObject);
00323     if (!NT_SUCCESS(Status))
00324     {
00325         DPRINT("Status %x\n", Status);
00326         return(Status);
00327     }
00328 
00329     KeInitializeEvent(&Event,
00330         NotificationEvent,
00331         FALSE);
00332 
00333     Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
00334         DeviceObject,
00335         NULL,
00336         0,
00337         &DiskGeometry,
00338         sizeof(DISK_GEOMETRY),
00339         FALSE,
00340         &Event,
00341         &StatusBlock);
00342     if (Irp == NULL)
00343     {
00344         ObDereferenceObject(FileObject);
00345         return(STATUS_INSUFFICIENT_RESOURCES);
00346     }
00347 
00348     Status = IoCallDriver(DeviceObject,
00349         Irp);
00350     if (Status == STATUS_PENDING)
00351     {
00352         KeWaitForSingleObject(&Event,
00353             Executive,
00354             KernelMode,
00355             FALSE,
00356             NULL);
00357         Status = StatusBlock.Status;
00358     }
00359     if (!NT_SUCCESS(Status))
00360     {
00361         if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
00362         {
00363             DiskGeometry.BytesPerSector = 512;
00364         }
00365         else
00366         {
00367             ObDereferenceObject(FileObject);
00368             return(Status);
00369         }
00370     }
00371 
00372     DPRINT("DiskGeometry.BytesPerSector: %d\n",
00373         DiskGeometry.BytesPerSector);
00374 
00375     if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
00376     {
00377         PDRIVE_LAYOUT_INFORMATION Buffer;
00378 
00379         /* Allocate a partition list for a single entry. */
00380         Buffer = ExAllocatePoolWithTag(NonPagedPool,
00381             sizeof(DRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM);
00382         if (Buffer != NULL)
00383         {
00384             RtlZeroMemory(Buffer,
00385                 sizeof(DRIVE_LAYOUT_INFORMATION));
00386             Buffer->PartitionCount = 1;
00387             *LayoutInfo = Buffer;
00388 
00389             Status = STATUS_SUCCESS;
00390         }
00391         else
00392         {
00393             Status = STATUS_UNSUCCESSFUL;
00394         }
00395     }
00396     else
00397     {
00398         /* Read the partition table */
00399         Status = IoReadPartitionTable(DeviceObject,
00400             DiskGeometry.BytesPerSector,
00401             TRUE,
00402             LayoutInfo);
00403     }
00404 
00405     ObDereferenceObject(FileObject);
00406 
00407     return(Status);
00408 }
00409 
00410 VOID
00411 FASTCALL
00412 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
00413                          IN PSTRING NtDeviceName,
00414                          OUT PUCHAR NtSystemPath,
00415                          OUT PSTRING NtSystemPathString)
00416 {
00417     PDRIVE_LAYOUT_INFORMATION *LayoutArray;
00418     PCONFIGURATION_INFORMATION ConfigInfo;
00419     OBJECT_ATTRIBUTES ObjectAttributes;
00420     IO_STATUS_BLOCK StatusBlock;
00421     UNICODE_STRING UnicodeString1;
00422     UNICODE_STRING UnicodeString2;
00423     HANDLE FileHandle;
00424     PWSTR Buffer1;
00425     PWSTR Buffer2;
00426     ULONG i, j, k;
00427     ULONG DiskNumber;
00428     ULONG RDisk;
00429     NTSTATUS Status;
00430     HANDLE hKey;
00431     ULONG Length;
00432     PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
00433     PREG_DISK_MOUNT_INFO DiskMountInfo;
00434     ULONG RDiskCount;
00435     UNICODE_STRING BootDevice;
00436 
00437     Status = RtlAnsiStringToUnicodeString(&BootDevice,
00438                                           NtDeviceName,
00439                                           TRUE);
00440 
00441     DPRINT("xHalIoAssignDriveLetters()\n");
00442 
00443     ConfigInfo = IoGetConfigurationInformation();
00444 
00445     RDiskCount = xHalpGetRDiskCount();
00446 
00447     DPRINT("RDiskCount %d\n", RDiskCount);
00448 
00449     Buffer1 = (PWSTR)ExAllocatePoolWithTag(PagedPool,
00450         64 * sizeof(WCHAR), TAG_FILE_SYSTEM);
00451     Buffer2 = (PWSTR)ExAllocatePoolWithTag(PagedPool,
00452         32 * sizeof(WCHAR), TAG_FILE_SYSTEM);
00453 
00454     PartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(PagedPool,
00455         sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO), TAG_FILE_SYSTEM);
00456 
00457     if (!Buffer1 || !Buffer2 || !PartialInformation) return;
00458 
00459     DiskMountInfo = (PREG_DISK_MOUNT_INFO) PartialInformation->Data;
00460 
00461     /* Open or Create the 'MountedDevices' key */
00462     RtlInitUnicodeString(&UnicodeString1, L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
00463     InitializeObjectAttributes(&ObjectAttributes,
00464         &UnicodeString1,
00465         OBJ_CASE_INSENSITIVE,
00466         NULL,
00467         NULL);
00468     Status = ZwOpenKey(&hKey,
00469         KEY_ALL_ACCESS,
00470         &ObjectAttributes);
00471     if (!NT_SUCCESS(Status))
00472     {
00473         Status = ZwCreateKey(&hKey,
00474             KEY_ALL_ACCESS,
00475             &ObjectAttributes,
00476             0,
00477             NULL,
00478             REG_OPTION_NON_VOLATILE,
00479             NULL);
00480     }
00481     if (!NT_SUCCESS(Status))
00482     {
00483         hKey = NULL;
00484         DPRINT("ZwCreateKey failed for %wZ, status=%x\n", &UnicodeString1, Status);
00485     }
00486 
00487     /* Create PhysicalDrive links */
00488     DPRINT("Physical disk drives: %d\n", ConfigInfo->DiskCount);
00489     for (i = 0; i < ConfigInfo->DiskCount; i++)
00490     {
00491         swprintf(Buffer1,
00492             L"\\Device\\Harddisk%d\\Partition0",
00493             i);
00494         RtlInitUnicodeString(&UnicodeString1,
00495             Buffer1);
00496 
00497         InitializeObjectAttributes(&ObjectAttributes,
00498             &UnicodeString1,
00499             0,
00500             NULL,
00501             NULL);
00502 
00503         Status = ZwOpenFile(&FileHandle,
00504             FILE_READ_DATA | SYNCHRONIZE,
00505             &ObjectAttributes,
00506             &StatusBlock,
00507             FILE_SHARE_READ,
00508             FILE_SYNCHRONOUS_IO_NONALERT);
00509         if (NT_SUCCESS(Status))
00510         {
00511             ZwClose(FileHandle);
00512 
00513             swprintf(Buffer2,
00514                 L"\\??\\PhysicalDrive%d",
00515                 i);
00516             RtlInitUnicodeString(&UnicodeString2,
00517                 Buffer2);
00518 
00519             DPRINT("Creating link: %S ==> %S\n",
00520                 Buffer2,
00521                 Buffer1);
00522 
00523             IoCreateSymbolicLink(&UnicodeString2,
00524                 &UnicodeString1);
00525         }
00526     }
00527 
00528     /* Initialize layout array */
00529     if (ConfigInfo->DiskCount == 0)
00530         goto end_assign_disks;
00531     LayoutArray = ExAllocatePoolWithTag(NonPagedPool,
00532         ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM);
00533     if (!LayoutArray)
00534     {
00535         ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM);
00536         ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
00537         ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
00538         if (hKey) ZwClose(hKey);
00539     }
00540 
00541     RtlZeroMemory(LayoutArray,
00542         ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
00543     for (i = 0; i < ConfigInfo->DiskCount; i++)
00544     {
00545         swprintf(Buffer1,
00546             L"\\Device\\Harddisk%d\\Partition0",
00547             i);
00548         RtlInitUnicodeString(&UnicodeString1,
00549             Buffer1);
00550 
00551         Status = xHalQueryDriveLayout(&UnicodeString1,
00552             &LayoutArray[i]);
00553         if (!NT_SUCCESS(Status))
00554         {
00555             DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n",
00556                 Status);
00557             LayoutArray[i] = NULL;
00558             continue;
00559         }
00560         /* We don't use the RewritePartition value while mounting the disks.
00561         * We use this value for marking pre-assigned (registry) partitions.
00562         */
00563         for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
00564         {
00565             LayoutArray[i]->PartitionEntry[j].RewritePartition = FALSE;
00566         }
00567     }
00568 
00569 #ifndef NDEBUG
00570     /* Dump layout array */
00571     for (i = 0; i < ConfigInfo->DiskCount; i++)
00572     {
00573         DPRINT("Harddisk %d:\n",
00574             i);
00575 
00576         if (LayoutArray[i] == NULL)
00577             continue;
00578 
00579         DPRINT("Logical partitions: %d\n",
00580             LayoutArray[i]->PartitionCount);
00581 
00582         for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
00583         {
00584             DPRINT("  %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n",
00585                 j,
00586                 LayoutArray[i]->PartitionEntry[j].PartitionNumber,
00587                 LayoutArray[i]->PartitionEntry[j].BootIndicator,
00588                 LayoutArray[i]->PartitionEntry[j].PartitionType,
00589                 LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart,
00590                 LayoutArray[i]->PartitionEntry[j].PartitionLength.QuadPart);
00591         }
00592     }
00593 #endif
00594 
00595     /* Assign pre-assigned (registry) partitions */
00596     if (hKey)
00597     {
00598         for (k = 2; k < 26; k++)
00599         {
00600             swprintf(Buffer1, DiskMountString, L'A' + k);
00601             RtlInitUnicodeString(&UnicodeString1, Buffer1);
00602             Status = ZwQueryValueKey(hKey,
00603                 &UnicodeString1,
00604                 KeyValuePartialInformation,
00605                 PartialInformation,
00606                 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO),
00607                 &Length);
00608             if (NT_SUCCESS(Status) &&
00609                 PartialInformation->Type == REG_BINARY &&
00610                 PartialInformation->DataLength == sizeof(REG_DISK_MOUNT_INFO))
00611             {
00612                 DPRINT("%wZ => %08x:%08x%08x\n", &UnicodeString1, DiskMountInfo->Signature,
00613                     DiskMountInfo->StartingOffset.u.HighPart, DiskMountInfo->StartingOffset.u.LowPart);
00614                 {
00615                     BOOLEAN Found = FALSE;
00616                     for (i = 0; i < ConfigInfo->DiskCount; i++)
00617                     {
00618                         DPRINT("%x\n", LayoutArray[i]->Signature);
00619                         if (LayoutArray[i] &&
00620                             LayoutArray[i]->Signature &&
00621                             LayoutArray[i]->Signature == DiskMountInfo->Signature)
00622                         {
00623                             for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
00624                             {
00625                                 if (LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart == DiskMountInfo->StartingOffset.QuadPart)
00626                                 {
00627                                     if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType) &&
00628                                         LayoutArray[i]->PartitionEntry[j].RewritePartition == FALSE)
00629                                     {
00630                                         swprintf(Buffer2,
00631                                             L"\\Device\\Harddisk%d\\Partition%d",
00632                                             i,
00633                                             LayoutArray[i]->PartitionEntry[j].PartitionNumber);
00634                                         RtlInitUnicodeString(&UnicodeString2,
00635                                             Buffer2);
00636 
00637                                         /* Assign drive */
00638                                         DPRINT("  %wZ\n", &UnicodeString2);
00639                                         Found = HalpAssignDrive(&UnicodeString2,
00640                                             k,
00641                                             DOSDEVICE_DRIVE_FIXED,
00642                                             DiskMountInfo->Signature,
00643                                             DiskMountInfo->StartingOffset,
00644                                             NULL,
00645                                             &BootDevice,
00646                                             NtSystemPath);
00647                                         /* Mark the partition as assigned */
00648                                         LayoutArray[i]->PartitionEntry[j].RewritePartition = TRUE;
00649                                     }
00650                                     break;
00651                                 }
00652                             }
00653                         }
00654                     }
00655                     if (Found == FALSE)
00656                     {
00657                         /* We didn't find a partition for this entry, remove them. */
00658                         Status = ZwDeleteValueKey(hKey, &UnicodeString1);
00659                     }
00660                 }
00661             }
00662         }
00663     }
00664 
00665     /* Assign bootable partition on first harddisk */
00666     DPRINT("Assigning bootable primary partition on first harddisk:\n");
00667     if (RDiskCount > 0)
00668     {
00669         Status = xHalpGetDiskNumberFromRDisk(0, &DiskNumber);
00670         if (NT_SUCCESS(Status) &&
00671             DiskNumber < ConfigInfo->DiskCount &&
00672             LayoutArray[DiskNumber])
00673         {
00674             /* Search for bootable partition */
00675             for (j = 0; j < NUM_PARTITION_TABLE_ENTRIES && j < LayoutArray[DiskNumber]->PartitionCount; j++)
00676             {
00677                 if ((LayoutArray[DiskNumber]->PartitionEntry[j].BootIndicator == TRUE) &&
00678                     IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
00679                 {
00680                     if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE)
00681                     {
00682                         swprintf(Buffer2,
00683                             L"\\Device\\Harddisk%lu\\Partition%d",
00684                             DiskNumber,
00685                             LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
00686                         RtlInitUnicodeString(&UnicodeString2,
00687                             Buffer2);
00688 
00689                         /* Assign drive */
00690                         DPRINT("  %wZ\n", &UnicodeString2);
00691                         HalpAssignDrive(&UnicodeString2,
00692                             AUTO_DRIVE,
00693                             DOSDEVICE_DRIVE_FIXED,
00694                             LayoutArray[DiskNumber]->Signature,
00695                             LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
00696                             hKey,
00697                             &BootDevice,
00698                             NtSystemPath);
00699                         /* Mark the partition as assigned */
00700                         LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
00701                     }
00702                     break;
00703                 }
00704             }
00705         }
00706     }
00707 
00708     /* Assign remaining primary partitions */
00709     DPRINT("Assigning remaining primary partitions:\n");
00710     for (RDisk = 0; RDisk < RDiskCount; RDisk++)
00711     {
00712         Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber);
00713         if (NT_SUCCESS(Status) &&
00714             DiskNumber < ConfigInfo->DiskCount &&
00715             LayoutArray[DiskNumber])
00716         {
00717             /* Search for primary partitions */
00718             for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++)
00719             {
00720                 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
00721                     IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
00722                 {
00723                     swprintf(Buffer2,
00724                         L"\\Device\\Harddisk%d\\Partition%d",
00725                         DiskNumber,
00726                         LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
00727                     RtlInitUnicodeString(&UnicodeString2,
00728                         Buffer2);
00729 
00730                     /* Assign drive */
00731                     DPRINT("  %wZ\n",
00732                         &UnicodeString2);
00733                     HalpAssignDrive(&UnicodeString2,
00734                         AUTO_DRIVE,
00735                         DOSDEVICE_DRIVE_FIXED,
00736                         LayoutArray[DiskNumber]->Signature,
00737                         LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
00738                         hKey,
00739                         &BootDevice,
00740                         NtSystemPath);
00741                     /* Mark the partition as assigned */
00742                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
00743                 }
00744             }
00745         }
00746     }
00747 
00748     /* Assign extended (logical) partitions */
00749     DPRINT("Assigning extended (logical) partitions:\n");
00750     for (RDisk = 0; RDisk < RDiskCount; RDisk++)
00751     {
00752         Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber);
00753         if (NT_SUCCESS(Status) &&
00754             DiskNumber < ConfigInfo->DiskCount &&
00755             LayoutArray[DiskNumber])
00756         {
00757             /* Search for extended partitions */
00758             for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++)
00759             {
00760                 if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) &&
00761                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
00762                     LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0)
00763                 {
00764                     swprintf(Buffer2,
00765                         L"\\Device\\Harddisk%d\\Partition%d",
00766                         DiskNumber,
00767                         LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
00768                     RtlInitUnicodeString(&UnicodeString2,
00769                         Buffer2);
00770 
00771                     /* Assign drive */
00772                     DPRINT("  %wZ\n",
00773                         &UnicodeString2);
00774                     HalpAssignDrive(&UnicodeString2,
00775                         AUTO_DRIVE,
00776                         DOSDEVICE_DRIVE_FIXED,
00777                         LayoutArray[DiskNumber]->Signature,
00778                         LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
00779                         hKey,
00780                         &BootDevice,
00781                         NtSystemPath);
00782                     /* Mark the partition as assigned */
00783                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
00784                 }
00785             }
00786         }
00787     }
00788 
00789     /* Assign remaining primary partitions without an arc-name */
00790     DPRINT("Assigning remaining primary partitions:\n");
00791     for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++)
00792     {
00793         if (LayoutArray[DiskNumber])
00794         {
00795             /* Search for primary partitions */
00796             for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++)
00797             {
00798                 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
00799                     IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
00800                 {
00801                     swprintf(Buffer2,
00802                         L"\\Device\\Harddisk%d\\Partition%d",
00803                         DiskNumber,
00804                         LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
00805                     RtlInitUnicodeString(&UnicodeString2,
00806                         Buffer2);
00807 
00808                     /* Assign drive */
00809                     DPRINT("  %wZ\n",
00810                         &UnicodeString2);
00811                     HalpAssignDrive(&UnicodeString2,
00812                         AUTO_DRIVE,
00813                         DOSDEVICE_DRIVE_FIXED,
00814                         LayoutArray[DiskNumber]->Signature,
00815                         LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
00816                         hKey,
00817                         &BootDevice,
00818                         NtSystemPath);
00819                     /* Mark the partition as assigned */
00820                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
00821                 }
00822             }
00823         }
00824     }
00825 
00826     /* Assign extended (logical) partitions without an arc-name */
00827     DPRINT("Assigning extended (logical) partitions:\n");
00828     for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++)
00829     {
00830         if (LayoutArray[DiskNumber])
00831         {
00832             /* Search for extended partitions */
00833             for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++)
00834             {
00835                 if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) &&
00836                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
00837                     LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0)
00838                 {
00839                     swprintf(Buffer2,
00840                         L"\\Device\\Harddisk%d\\Partition%d",
00841                         DiskNumber,
00842                         LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
00843                     RtlInitUnicodeString(&UnicodeString2,
00844                         Buffer2);
00845 
00846                     /* Assign drive */
00847                     DPRINT("  %wZ\n",
00848                         &UnicodeString2);
00849                     HalpAssignDrive(&UnicodeString2,
00850                         AUTO_DRIVE,
00851                         DOSDEVICE_DRIVE_FIXED,
00852                         LayoutArray[DiskNumber]->Signature,
00853                         LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
00854                         hKey,
00855                         &BootDevice,
00856                         NtSystemPath);
00857                     /* Mark the partition as assigned */
00858                     LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
00859                 }
00860             }
00861         }
00862     }
00863 
00864     /* Assign removable disk drives */
00865     DPRINT("Assigning removable disk drives:\n");
00866     for (i = 0; i < ConfigInfo->DiskCount; i++)
00867     {
00868         if (LayoutArray[i])
00869         {
00870             /* Search for virtual partitions */
00871             if (LayoutArray[i]->PartitionCount == 1 &&
00872                 LayoutArray[i]->PartitionEntry[0].PartitionType == 0)
00873             {
00874                 swprintf(Buffer2,
00875                     L"\\Device\\Harddisk%d\\Partition1",
00876                     i);
00877                 RtlInitUnicodeString(&UnicodeString2,
00878                     Buffer2);
00879 
00880                 /* Assign drive */
00881                 DPRINT("  %wZ\n",
00882                     &UnicodeString2);
00883                 HalpAssignDrive(&UnicodeString2,
00884                     AUTO_DRIVE,
00885                     DOSDEVICE_DRIVE_REMOVABLE,
00886                     0,
00887                     RtlConvertLongToLargeInteger(0),
00888                     hKey,
00889                     &BootDevice,
00890                     NtSystemPath);
00891             }
00892         }
00893     }
00894 
00895     /* Free layout array */
00896     for (i = 0; i < ConfigInfo->DiskCount; i++)
00897     {
00898         if (LayoutArray[i] != NULL)
00899             ExFreePoolWithTag(LayoutArray[i], TAG_FILE_SYSTEM);
00900     }
00901     ExFreePoolWithTag(LayoutArray, TAG_FILE_SYSTEM);
00902 end_assign_disks:
00903 
00904     /* Assign floppy drives */
00905     DPRINT("Floppy drives: %d\n", ConfigInfo->FloppyCount);
00906     for (i = 0; i < ConfigInfo->FloppyCount; i++)
00907     {
00908         swprintf(Buffer1,
00909             L"\\Device\\Floppy%d",
00910             i);
00911         RtlInitUnicodeString(&UnicodeString1,
00912             Buffer1);
00913 
00914         /* Assign drive letters A: or B: or first free drive letter */
00915         DPRINT("  %wZ\n",
00916             &UnicodeString1);
00917         HalpAssignDrive(&UnicodeString1,
00918             (i < 2) ? i : AUTO_DRIVE,
00919             DOSDEVICE_DRIVE_REMOVABLE,
00920             0,
00921             RtlConvertLongToLargeInteger(0),
00922             hKey,
00923             &BootDevice,
00924             NtSystemPath);
00925     }
00926 
00927     /* Assign cdrom drives */
00928     DPRINT("CD-Rom drives: %d\n", ConfigInfo->CdRomCount);
00929     for (i = 0; i < ConfigInfo->CdRomCount; i++)
00930     {
00931         swprintf(Buffer1,
00932             L"\\Device\\CdRom%d",
00933             i);
00934         RtlInitUnicodeString(&UnicodeString1,
00935             Buffer1);
00936 
00937         /* Assign first free drive letter */
00938         DPRINT("  %wZ\n", &UnicodeString1);
00939         HalpAssignDrive(&UnicodeString1,
00940             AUTO_DRIVE,
00941             DOSDEVICE_DRIVE_CDROM,
00942             0,
00943             RtlConvertLongToLargeInteger(0),
00944             hKey,
00945             &BootDevice,
00946             NtSystemPath);
00947     }
00948 
00949     /* Anything else to do? */
00950 
00951     ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM);
00952     ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
00953     ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
00954     if (hKey)
00955     {
00956         ZwClose(hKey);
00957     }
00958 }
00959 
00960 #endif
00961 
00962 /* PRIVATE FUNCTIONS *********************************************************/
00963 
00964 NTSTATUS
00965 NTAPI
00966 HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject,
00967                     IN PDISK_GEOMETRY Geometry,
00968                     OUT PULONGLONG RealSectorCount)
00969 {
00970     PIRP Irp;
00971     IO_STATUS_BLOCK IoStatusBlock;
00972     PKEVENT Event;
00973     NTSTATUS Status;
00974     PARTITION_INFORMATION PartitionInfo;
00975     PAGED_CODE();
00976 
00977     /* Allocate a non-paged event */
00978     Event = ExAllocatePoolWithTag(NonPagedPool,
00979                                      sizeof(KEVENT),
00980                                      TAG_FILE_SYSTEM);
00981     if (!Event) return STATUS_INSUFFICIENT_RESOURCES;
00982 
00983     /* Initialize it */
00984     KeInitializeEvent(Event, NotificationEvent, FALSE);
00985 
00986     /* Build the IRP */
00987     Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
00988                                              DeviceObject,
00989                                              NULL,
00990                                              0UL,
00991                                              Geometry,
00992                                              sizeof(DISK_GEOMETRY),
00993                                              FALSE,
00994                                              Event,
00995                                              &IoStatusBlock);
00996     if (!Irp)
00997     {
00998         /* Fail, free the event */
00999         ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
01000         return STATUS_INSUFFICIENT_RESOURCES;
01001     }
01002 
01003     /* Call the driver and check if it's pending */
01004     Status = IoCallDriver(DeviceObject, Irp);
01005     if (Status == STATUS_PENDING)
01006     {
01007         /* Wait on the driver */
01008         KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
01009         Status = IoStatusBlock.Status;
01010     }
01011 
01012     /* Check if the driver returned success */
01013     if(NT_SUCCESS(Status))
01014     {
01015         /* Build another IRP */
01016         Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
01017                                                  DeviceObject,
01018                                                  NULL,
01019                                                  0UL,
01020                                                  &PartitionInfo,
01021                                                  sizeof(PARTITION_INFORMATION),
01022                                                  FALSE,
01023                                                  Event,
01024                                                  &IoStatusBlock);
01025         if (!Irp)
01026         {
01027             /* Fail, free the event */
01028             ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
01029             return STATUS_INSUFFICIENT_RESOURCES;
01030         }
01031 
01032         /* Call the driver and check if it's pending */
01033         Status = IoCallDriver(DeviceObject, Irp);
01034         if (Status == STATUS_PENDING)
01035         {
01036             /* Wait on the driver */
01037             KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
01038             Status = IoStatusBlock.Status;
01039         }
01040 
01041         /* Check if the driver returned success */
01042         if(NT_SUCCESS(Status))
01043         {
01044             /* Get the number of sectors */
01045             *RealSectorCount = (PartitionInfo.PartitionLength.QuadPart /
01046                                 Geometry->BytesPerSector);
01047         }
01048     }
01049 
01050     /* Free the event and return the Status */
01051     ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
01052     return Status;
01053 }
01054 
01055 BOOLEAN
01056 NTAPI
01057 HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry,
01058                           IN ULONGLONG MaxOffset,
01059                           IN ULONGLONG MaxSector)
01060 {
01061     ULONGLONG EndingSector;
01062     PAGED_CODE();
01063 
01064     /* Unused partitions are considered valid */
01065     if (Entry->PartitionType == PARTITION_ENTRY_UNUSED) return TRUE;
01066 
01067     /* Get the last sector of the partition */
01068     EndingSector = GET_STARTING_SECTOR(Entry) +  GET_PARTITION_LENGTH(Entry);
01069 
01070     /* Check if it's more then the maximum sector */
01071     if (EndingSector > MaxSector)
01072     {
01073         /* Invalid partition */
01074         DPRINT1("FSTUB: entry is invalid\n");
01075         DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
01076         DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
01077         DPRINT1("FSTUB: end %#I64x\n", EndingSector);
01078         DPRINT1("FSTUB: max %#I64x\n", MaxSector);
01079         return FALSE;
01080     }
01081     else if(GET_STARTING_SECTOR(Entry) > MaxOffset)
01082     {
01083         /* Invalid partition */
01084         DPRINT1("FSTUB: entry is invalid\n");
01085         DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
01086         DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
01087         DPRINT1("FSTUB: end %#I64x\n", EndingSector);
01088         DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset);
01089         return FALSE;
01090     }
01091 
01092     /* It's fine, return success */
01093     return TRUE;
01094 }
01095 
01096 VOID
01097 NTAPI
01098 HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset,
01099                        IN PLARGE_INTEGER PartitionLength,
01100                        IN CCHAR ShiftCount,
01101                        IN ULONG SectorsPerTrack,
01102                        IN ULONG NumberOfTracks,
01103                        IN ULONG ConventionalCylinders,
01104                        OUT PPARTITION_DESCRIPTOR PartitionDescriptor)
01105 {
01106     LARGE_INTEGER FirstSector, SectorCount;
01107     ULONG LastSector, Remainder, SectorsPerCylinder;
01108     ULONG StartingCylinder, EndingCylinder;
01109     ULONG StartingTrack, EndingTrack;
01110     ULONG StartingSector, EndingSector;
01111     PAGED_CODE();
01112 
01113     /* Calculate the number of sectors for each cylinder */
01114     SectorsPerCylinder = SectorsPerTrack * NumberOfTracks;
01115 
01116     /* Calculate the first sector, and the sector count */
01117     FirstSector.QuadPart = PartitionOffset->QuadPart >> ShiftCount;
01118     SectorCount.QuadPart = PartitionLength->QuadPart >> ShiftCount;
01119 
01120     /* Now calculate the last sector */
01121     LastSector = FirstSector.LowPart + SectorCount.LowPart - 1;
01122 
01123     /* Calculate the first and last cylinders */
01124     StartingCylinder = FirstSector.LowPart / SectorsPerCylinder;
01125     EndingCylinder = LastSector / SectorsPerCylinder;
01126 
01127     /* Set the default number of cylinders */
01128     if (!ConventionalCylinders) ConventionalCylinders = 1024;
01129 
01130     /* Normalize the values */
01131     if (StartingCylinder >= ConventionalCylinders)
01132     {
01133         /* Set the maximum to 1023 */
01134         StartingCylinder = ConventionalCylinders - 1;
01135     }
01136     if (EndingCylinder >= ConventionalCylinders)
01137     {
01138         /* Set the maximum to 1023 */
01139         EndingCylinder = ConventionalCylinders - 1;
01140     }
01141 
01142     /* Calculate the starting head and sector that still remain */
01143     Remainder = FirstSector.LowPart % SectorsPerCylinder;
01144     StartingTrack = Remainder / SectorsPerTrack;
01145     StartingSector = Remainder % SectorsPerTrack;
01146 
01147     /* Calculate the ending head and sector that still remain */
01148     Remainder = LastSector % SectorsPerCylinder;
01149     EndingTrack = Remainder / SectorsPerTrack;
01150     EndingSector = Remainder % SectorsPerTrack;
01151 
01152     /* Set cylinder data for the MSB */
01153     PartitionDescriptor->StartingCylinderMsb = (UCHAR)StartingCylinder;
01154     PartitionDescriptor->EndingCylinderMsb = (UCHAR)EndingCylinder;
01155 
01156     /* Set the track data */
01157     PartitionDescriptor->StartingTrack = (UCHAR)StartingTrack;
01158     PartitionDescriptor->EndingTrack = (UCHAR)EndingTrack;
01159 
01160     /* Update cylinder data for the LSB */
01161     StartingCylinder = ((StartingSector + 1) & 0x3F) |
01162                        ((StartingCylinder >> 2) & 0xC0);
01163     EndingCylinder = ((EndingSector + 1) & 0x3F) |
01164                      ((EndingCylinder >> 2) & 0xC0);
01165 
01166     /* Set the cylinder data for the LSB */
01167     PartitionDescriptor->StartingCylinderLsb = (UCHAR)StartingCylinder;
01168     PartitionDescriptor->EndingCylinderLsb = (UCHAR)EndingCylinder;
01169 }
01170 
01171 VOID
01172 FASTCALL
01173 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject,
01174                        IN PULONG ConventionalCylinders,
01175                        IN PLONGLONG DiskSize)
01176 {
01177     PDISK_GEOMETRY DiskGeometry = NULL;
01178     PIO_STATUS_BLOCK IoStatusBlock = NULL;
01179     PKEVENT Event = NULL;
01180     PIRP Irp;
01181     NTSTATUS Status;
01182 
01183     /* Set defaults */
01184     *ConventionalCylinders = 0;
01185     *DiskSize = 0;
01186 
01187     /* Allocate the structure in nonpaged pool */
01188     DiskGeometry = ExAllocatePoolWithTag(NonPagedPool,
01189                                          sizeof(DISK_GEOMETRY),
01190                                          TAG_FILE_SYSTEM);
01191     if (!DiskGeometry) goto Cleanup;
01192 
01193     /* Allocate the status block in nonpaged pool */
01194     IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool,
01195                                           sizeof(IO_STATUS_BLOCK),
01196                                           TAG_FILE_SYSTEM);
01197     if (!IoStatusBlock) goto Cleanup;
01198 
01199     /* Allocate the event in nonpaged pool too */
01200     Event = ExAllocatePoolWithTag(NonPagedPool,
01201                                   sizeof(KEVENT),
01202                                   TAG_FILE_SYSTEM);
01203     if (!Event) goto Cleanup;
01204 
01205     /* Initialize the event */
01206     KeInitializeEvent(Event, NotificationEvent, FALSE);
01207 
01208     /* Build the IRP */
01209     Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
01210                                         DeviceObject,
01211                                         NULL,
01212                                         0,
01213                                         DiskGeometry,
01214                                         sizeof(DISK_GEOMETRY),
01215                                         FALSE,
01216                                         Event,
01217                                         IoStatusBlock);
01218     if (!Irp) goto Cleanup;
01219 
01220     /* Now call the driver */
01221     Status = IoCallDriver(DeviceObject, Irp);
01222     if (Status == STATUS_PENDING)
01223     {
01224         /* Wait for it to complete */
01225         KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
01226         Status = IoStatusBlock->Status;
01227     }
01228 
01229     /* Check driver status */
01230     if (NT_SUCCESS(Status))
01231     {
01232         /* Return the cylinder count */
01233         *ConventionalCylinders = DiskGeometry->Cylinders.LowPart;
01234 
01235         /* Make sure it's not larger then 1024 */
01236         if (DiskGeometry->Cylinders.LowPart >= 1024)
01237         {
01238             /* Otherwise, normalize the value */
01239             *ConventionalCylinders = 1024;
01240         }
01241 
01242         /* Calculate the disk size */
01243         *DiskSize = DiskGeometry->Cylinders.QuadPart *
01244                     DiskGeometry->TracksPerCylinder *
01245                     DiskGeometry->SectorsPerTrack *
01246                     DiskGeometry->BytesPerSector;
01247     }
01248 
01249 Cleanup:
01250     /* Free all the pointers */
01251     if (Event) ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
01252     if (IoStatusBlock) ExFreePoolWithTag(IoStatusBlock, TAG_FILE_SYSTEM);
01253     if (DiskGeometry) ExFreePoolWithTag(DiskGeometry, TAG_FILE_SYSTEM);
01254     return;
01255 }
01256 
01257 VOID
01258 FASTCALL
01259 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
01260                IN ULONG SectorSize,
01261                IN ULONG MbrTypeIdentifier,
01262                OUT PVOID *MbrBuffer)
01263 {
01264     LARGE_INTEGER Offset;
01265     PUCHAR Buffer;
01266     ULONG BufferSize;
01267     KEVENT Event;
01268     IO_STATUS_BLOCK IoStatusBlock;
01269     PIRP Irp;
01270     PPARTITION_DESCRIPTOR PartitionDescriptor;
01271     NTSTATUS Status;
01272     PIO_STACK_LOCATION IoStackLocation;
01273     Offset.QuadPart = 0;
01274 
01275     /* Assume failure */
01276     *MbrBuffer = NULL;
01277 
01278     /* Normalize the buffer size */
01279     BufferSize = max(SectorSize, 512);
01280 
01281     /* Allocate the buffer */
01282     Buffer = ExAllocatePoolWithTag(NonPagedPool,
01283                                        PAGE_SIZE > BufferSize ?
01284                                        PAGE_SIZE : BufferSize,
01285                                        TAG_FILE_SYSTEM);
01286     if (!Buffer) return;
01287 
01288     /* Initialize the Event */
01289     KeInitializeEvent(&Event, NotificationEvent, FALSE);
01290 
01291     /* Build the IRP */
01292     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
01293                                        DeviceObject,
01294                                        Buffer,
01295                                        BufferSize,
01296                                        &Offset,
01297                                        &Event,
01298                                        &IoStatusBlock);
01299     if (!Irp)
01300     {
01301         /* Failed */
01302         ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
01303         return;
01304     }
01305 
01306     /* Make sure to override volume verification */
01307     IoStackLocation = IoGetNextIrpStackLocation(Irp);
01308     IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
01309 
01310     /* Call the driver */
01311     Status = IoCallDriver(DeviceObject, Irp);
01312     if (Status == STATUS_PENDING)
01313     {
01314         /* Wait for completion */
01315         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
01316         Status = IoStatusBlock.Status;
01317     }
01318 
01319     /* Check driver Status */
01320     if (NT_SUCCESS(Status))
01321     {
01322         /* Validate the MBR Signature */
01323         if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
01324         {
01325             /* Failed */
01326             ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
01327             return;
01328         }
01329 
01330         /* Get the partition entry */
01331         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
01332                                &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
01333 
01334         /* Make sure it's what the caller wanted */
01335         if (PartitionDescriptor->PartitionType != MbrTypeIdentifier)
01336         {
01337             /* It's not, free our buffer */
01338             ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
01339         }
01340         else
01341         {
01342             /* Check if this is a secondary entry */
01343             if (PartitionDescriptor->PartitionType == 0x54)
01344             {
01345                 /* Return our buffer, but at sector 63 */
01346                 *(PULONG)Buffer = 63;
01347                 *MbrBuffer = Buffer;
01348             }
01349             else if (PartitionDescriptor->PartitionType == 0x55)
01350             {
01351                 /* EZ Drive, return the buffer directly */
01352                 *MbrBuffer = Buffer;
01353             }
01354             else
01355             {
01356                 /* Otherwise crash on debug builds */
01357                 ASSERT(PartitionDescriptor->PartitionType == 0x55);
01358             }
01359         }
01360     }
01361 }
01362 
01363 VOID
01364 NTAPI
01365 FstubFixupEfiPartition(IN PPARTITION_DESCRIPTOR PartitionDescriptor,
01366                        IN ULONGLONG MaxOffset)
01367 {
01368     ULONG PartitionMaxOffset, PartitionLength;
01369     PAGED_CODE();
01370 
01371     /* Compute partition length (according to MBR entry) */
01372     PartitionMaxOffset = GET_STARTING_SECTOR(PartitionDescriptor) + GET_PARTITION_LENGTH(PartitionDescriptor);
01373     /* In case the partition length goes beyond disk size... */
01374     if (PartitionMaxOffset > MaxOffset)
01375     {
01376         /* Resize partition to its maximum real length */
01377         PartitionLength = (ULONG)(PartitionMaxOffset - GET_STARTING_SECTOR(PartitionDescriptor));
01378         SET_PARTITION_LENGTH(PartitionDescriptor, PartitionLength);
01379     }
01380 }
01381 
01382 NTSTATUS
01383 FASTCALL
01384 xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
01385                          IN ULONG SectorSize,
01386                          IN BOOLEAN ReturnRecognizedPartitions,
01387                          IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
01388 {
01389     KEVENT Event;
01390     IO_STATUS_BLOCK IoStatusBlock;
01391     PIRP Irp;
01392     PPARTITION_DESCRIPTOR PartitionDescriptor;
01393     CCHAR Entry;
01394     NTSTATUS Status;
01395     PPARTITION_INFORMATION PartitionInfo;
01396     PUCHAR Buffer = NULL;
01397     ULONG BufferSize = 2048, InputSize;
01398     PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo = NULL;
01399     LONG j = -1, i = -1, k;
01400     DISK_GEOMETRY DiskGeometry;
01401     LONGLONG EndSector, MaxSector, StartOffset;
01402     ULONGLONG MaxOffset;
01403     LARGE_INTEGER Offset, VolumeOffset;
01404     BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE, MbrFound = FALSE;
01405     BOOLEAN IsValid, IsEmpty = TRUE;
01406     PVOID MbrBuffer;
01407     PIO_STACK_LOCATION IoStackLocation;
01408     PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer;
01409     UCHAR PartitionType;
01410     LARGE_INTEGER HiddenSectors64;
01411     VolumeOffset.QuadPart = Offset.QuadPart = 0;
01412     PAGED_CODE();
01413 
01414     /* Allocate the buffer */
01415     *PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
01416                                              BufferSize,
01417                                              TAG_FILE_SYSTEM);
01418     if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES;
01419 
01420     /* Normalize the buffer size */
01421     InputSize = max(512, SectorSize);
01422 
01423     /* Check for EZ Drive */
01424     HalExamineMBR(DeviceObject, InputSize, 0x55, &MbrBuffer);
01425     if (MbrBuffer)
01426     {
01427         /* EZ Drive found, bias the offset */
01428         IsEzDrive = TRUE;
01429         ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
01430         Offset.QuadPart = 512;
01431     }
01432 
01433     /* Get drive geometry */
01434     Status = HalpGetFullGeometry(DeviceObject, &DiskGeometry, &MaxOffset);
01435     if (!NT_SUCCESS(Status))
01436     {
01437         ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
01438         *PartitionBuffer = NULL;
01439         return Status;
01440     }
01441 
01442     /* Get the end and maximum sector */
01443     EndSector = MaxOffset;
01444     MaxSector = MaxOffset << 1;
01445     DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n",
01446             MaxOffset, MaxSector);
01447 
01448     /* Allocate our buffer */
01449     Buffer = ExAllocatePoolWithTag(NonPagedPool, InputSize, TAG_FILE_SYSTEM);
01450     if (!Buffer)
01451     {
01452         /* Fail, free the input buffer */
01453         ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
01454         *PartitionBuffer = NULL;
01455         return STATUS_INSUFFICIENT_RESOURCES;
01456     }
01457 
01458     /* Start partition loop */
01459     do
01460     {
01461         /* Assume the partition is valid */
01462         IsValid = TRUE;
01463 
01464         /* Initialize the event */
01465         KeInitializeEvent(&Event, NotificationEvent, FALSE);
01466 
01467         /* Clear the buffer and build the IRP */
01468         RtlZeroMemory(Buffer, InputSize);
01469         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
01470                                            DeviceObject,
01471                                            Buffer,
01472                                            InputSize,
01473                                            &Offset,
01474                                            &Event,
01475                                            &IoStatusBlock);
01476         if (!Irp)
01477         {
01478             /* Failed */
01479             Status = STATUS_INSUFFICIENT_RESOURCES;
01480             break;
01481         }
01482 
01483         /* Make sure to disable volume verification */
01484         IoStackLocation = IoGetNextIrpStackLocation(Irp);
01485         IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
01486 
01487         /* Call the driver */
01488         Status = IoCallDriver(DeviceObject, Irp);
01489         if (Status == STATUS_PENDING)
01490         {
01491             /* Wait for completion */
01492             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
01493             Status = IoStatusBlock.Status;
01494         }
01495 
01496         /* Normalize status code and check for failure */
01497         if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS;
01498         if (!NT_SUCCESS(Status)) break;
01499 
01500         /* If we biased for EZ-Drive, unbias now */
01501         if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
01502 
01503         /* Make sure this is a valid MBR */
01504         if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
01505         {
01506             /* It's not, fail */
01507             DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "
01508                     "partition table %d\n", j + 1);
01509             break;
01510         }
01511 
01512         /* At this point we have a valid MBR */
01513         MbrFound = TRUE;
01514 
01515         /* Check if we weren't given an offset */
01516         if (!Offset.QuadPart)
01517         {
01518             /* Then read the signature off the disk */
01519             (*PartitionBuffer)->Signature =  ((PULONG)Buffer)
01520                                              [PARTITION_TABLE_OFFSET / 2 - 1];
01521         }
01522 
01523         /* Get the partition descriptor array */
01524         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
01525                                &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
01526 
01527         /* Start looping partitions */
01528         j++;
01529         DPRINT("FSTUB: Partition Table %d:\n", j);
01530         for (Entry = 1, k = 0; Entry <= 4; Entry++, PartitionDescriptor++)
01531         {
01532             /* Get the partition type */
01533             PartitionType = PartitionDescriptor->PartitionType;
01534 
01535             /* Print debug messages */
01536             DPRINT("Partition Entry %d,%d: type %#x %s\n",
01537                     j,
01538                     Entry,
01539                     PartitionType,
01540                     (PartitionDescriptor->ActiveFlag) ? "Active" : "");
01541             DPRINT("\tOffset %#08lx for %#08lx Sectors\n",
01542                     GET_STARTING_SECTOR(PartitionDescriptor),
01543                     GET_PARTITION_LENGTH(PartitionDescriptor));
01544 
01545             /* Check whether we're facing a protective MBR */
01546             if (PartitionType == EFI_PMBR_OSTYPE_EFI)
01547             {
01548                 /* Partition length might be bigger than disk size */
01549                 FstubFixupEfiPartition(PartitionDescriptor,
01550                                        MaxOffset);
01551             }
01552 
01553             /* Make sure that the partition is valid, unless it's the first */
01554             if (!(HalpIsValidPartitionEntry(PartitionDescriptor,
01555                                             MaxOffset,
01556                                             MaxSector)) && !(j))
01557             {
01558                 /* It's invalid, so fail */
01559                 IsValid = FALSE;
01560                 break;
01561             }
01562 
01563             /* Check if it's a container */
01564             if (IsContainerPartition(PartitionType))
01565             {
01566                 /* Increase the count of containers */
01567                 if (++k != 1)
01568                 {
01569                     /* More then one table is invalid */
01570                     DPRINT1("FSTUB: Multiple container partitions found in "
01571                             "partition table %d\n - table is invalid\n",
01572                             j);
01573                     IsValid = FALSE;
01574                     break;
01575                 }
01576             }
01577 
01578             /* Check if the partition is supposedly empty */
01579             if (IsEmpty)
01580             {
01581                 /* But check if it actually has a start and/or length */
01582                 if ((GET_STARTING_SECTOR(PartitionDescriptor)) ||
01583                     (GET_PARTITION_LENGTH(PartitionDescriptor)))
01584                 {
01585                     /* So then it's not really empty */
01586                     IsEmpty = FALSE;
01587                 }
01588             }
01589 
01590             /* Check if the caller wanted only recognized partitions */
01591             if (ReturnRecognizedPartitions)
01592             {
01593                 /* Then check if this one is unused, or a container */
01594                 if ((PartitionType == PARTITION_ENTRY_UNUSED) ||
01595                     IsContainerPartition(PartitionType))
01596                 {
01597                     /* Skip it, since the caller doesn't want it */
01598                     continue;
01599                 }
01600             }
01601 
01602             /* Increase the structure count and check if they can fit */
01603             if ((sizeof(DRIVE_LAYOUT_INFORMATION) +
01604                  (++i * sizeof(PARTITION_INFORMATION))) >
01605                 BufferSize)
01606             {
01607                 /* Allocate a new buffer that's twice as big */
01608                 DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool,
01609                                                         BufferSize << 1,
01610                                                         TAG_FILE_SYSTEM);
01611                 if (!DriveLayoutInfo)
01612                 {
01613                     /* Out of memory, unto this extra structure */
01614                     --i;
01615                     Status = STATUS_INSUFFICIENT_RESOURCES;
01616                     break;
01617                 }
01618 
01619                 /* Copy the contents of the old buffer */
01620                 RtlMoveMemory(DriveLayoutInfo,
01621                               *PartitionBuffer,
01622                               BufferSize);
01623 
01624                 /* Free the old buffer and set this one as the new one */
01625                 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
01626                 *PartitionBuffer = DriveLayoutInfo;
01627 
01628                 /* Double the size */
01629                 BufferSize <<= 1;
01630             }
01631 
01632             /* Now get the current structure being filled and initialize it */
01633             PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i];
01634             PartitionInfo->PartitionType = PartitionType;
01635             PartitionInfo->RewritePartition = FALSE;
01636 
01637             /* Check if we're dealing with a partition that's in use */
01638             if (PartitionType != PARTITION_ENTRY_UNUSED)
01639             {
01640                 /* Check if it's bootable */
01641                 PartitionInfo->BootIndicator = PartitionDescriptor->
01642                                                ActiveFlag & 0x80 ?
01643                                                TRUE : FALSE;
01644 
01645                 /* Check if its' a container */
01646                 if (IsContainerPartition(PartitionType))
01647                 {
01648                     /* Then don't recognize it and use the volume offset */
01649                     PartitionInfo->RecognizedPartition = FALSE;
01650                     StartOffset = VolumeOffset.QuadPart;
01651                 }
01652                 else
01653                 {
01654                     /* Then recognize it and use the partition offset */
01655                     PartitionInfo->RecognizedPartition = TRUE;
01656                     StartOffset = Offset.QuadPart;
01657                 }
01658 
01659                 /* Get the starting offset */
01660                 PartitionInfo->StartingOffset.QuadPart =
01661                     StartOffset +
01662                     UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor),
01663                                   SectorSize);
01664 
01665                 /* Calculate the number of hidden sectors */
01666                 HiddenSectors64.QuadPart = (PartitionInfo->
01667                                             StartingOffset.QuadPart -
01668                                             StartOffset) /
01669                                             SectorSize;
01670                 PartitionInfo->HiddenSectors = HiddenSectors64.LowPart;
01671 
01672                 /* Get the partition length */
01673                 PartitionInfo->PartitionLength.QuadPart =
01674                     UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor),
01675                                   SectorSize);
01676 
01677                 /* FIXME: REACTOS HACK */
01678                 PartitionInfo->PartitionNumber = i + 1;
01679             }
01680             else
01681             {
01682                 /* Otherwise, clear all the relevant fields */
01683                 PartitionInfo->BootIndicator = FALSE;
01684                 PartitionInfo->RecognizedPartition = FALSE;
01685                 PartitionInfo->StartingOffset.QuadPart = 0;
01686                 PartitionInfo->PartitionLength.QuadPart = 0;
01687                 PartitionInfo->HiddenSectors = 0;
01688 
01689                 /* FIXME: REACTOS HACK */
01690                 PartitionInfo->PartitionNumber = 0;
01691             }
01692         }
01693 
01694         /* Finish debug log, and check for failure */
01695         DPRINT("\n");
01696         if (!NT_SUCCESS(Status)) break;
01697 
01698         /* Also check if we hit an invalid entry here */
01699         if (!IsValid)
01700         {
01701             /* We did, so break out of the loop minus one entry */
01702             j--;
01703             break;
01704         }
01705 
01706         /* Reset the offset */
01707         Offset.QuadPart = 0;
01708 
01709         /* Go back to the descriptor array and loop it */
01710         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
01711                                &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
01712         for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
01713         {
01714             /* Check if this is a container partition, since we skipped them */
01715             if (IsContainerPartition(PartitionDescriptor->PartitionType))
01716             {
01717                 /* Get its offset */
01718                 Offset.QuadPart = VolumeOffset.QuadPart +
01719                                   UInt32x32To64(
01720                                      GET_STARTING_SECTOR(PartitionDescriptor),
01721                                      SectorSize);
01722 
01723                 /* If this is a primary partition, this is the volume offset */
01724                 if (IsPrimary) VolumeOffset = Offset;
01725 
01726                 /* Also update the maximum sector */
01727                 MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor);
01728                 DPRINT1("FSTUB: MaxSector now = %#08lx\n", MaxSector);
01729                 break;
01730             }
01731         }
01732 
01733         /* Loop the next partitions, which are not primary anymore */
01734         IsPrimary = FALSE;
01735     } while (Offset.HighPart | Offset.LowPart);
01736 
01737     /* Check if this is a removable device that's probably a super-floppy */
01738     if ((DiskGeometry.MediaType == RemovableMedia) &&
01739         !(j) &&
01740         (MbrFound) &&
01741         (IsEmpty))
01742     {
01743         /* Read the jump bytes to detect super-floppy */
01744         if ((BootSectorInfo->JumpByte[0] == 0xeb) ||
01745             (BootSectorInfo->JumpByte[0] == 0xe9))
01746         {
01747             /* Super floppes don't have typical MBRs, so skip them */
01748             DPRINT1("FSTUB: Jump byte %#x found along with empty partition "
01749                     "table - disk is a super floppy and has no valid MBR\n",
01750                     BootSectorInfo->JumpByte);
01751             j = -1;
01752         }
01753     }
01754 
01755     /* Check if we're still at partition -1 */
01756     if (j == -1)
01757     {
01758         /* The likely cause is the super floppy detection above */
01759         if ((MbrFound) || (DiskGeometry.MediaType == RemovableMedia))
01760         {
01761             /* Print out debugging information */
01762             DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "
01763                     "super-floppy\n",
01764                     DeviceObject);
01765             DPRINT1("FSTUB: Drive has %#08lx sectors and is %#016I64x "
01766                     "bytes large\n",
01767                     EndSector, EndSector * DiskGeometry.BytesPerSector);
01768 
01769             /* We should at least have some sectors */
01770             if (EndSector > 0)
01771             {
01772                 /* Get the entry we'll use */
01773                 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0];
01774 
01775                 /* Fill it out with data for a super-floppy */
01776                 PartitionInfo->RewritePartition = FALSE;
01777                 PartitionInfo->RecognizedPartition = TRUE;
01778                 PartitionInfo->PartitionType = PARTITION_FAT_16;
01779                 PartitionInfo->BootIndicator = FALSE;
01780                 PartitionInfo->HiddenSectors = 0;
01781                 PartitionInfo->StartingOffset.QuadPart = 0;
01782                 PartitionInfo->PartitionLength.QuadPart = (EndSector *
01783                                                            DiskGeometry.
01784                                                            BytesPerSector);
01785 
01786                 /* FIXME: REACTOS HACK */
01787                 PartitionInfo->PartitionNumber = 0;
01788 
01789                 /* Set the signature and set the count back to 0 */
01790                 (*PartitionBuffer)->Signature = 1;
01791                 i = 0;
01792             }
01793         }
01794         else
01795         {
01796             /* Otherwise, this isn't a super floppy, so set an invalid count */
01797             i = -1;
01798         }
01799     }
01800 
01801     /* Set the partition count */
01802     (*PartitionBuffer)->PartitionCount = ++i;
01803 
01804     /* If we have no count, delete the signature */
01805     if (!i) (*PartitionBuffer)->Signature = 0;
01806 
01807     /* Free the buffer and check for success */
01808     if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
01809     if (!NT_SUCCESS(Status)) ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
01810 
01811     /* Return status */
01812     return Status;
01813 }
01814 
01815 NTSTATUS
01816 FASTCALL
01817 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
01818                               IN ULONG SectorSize,
01819                               IN ULONG PartitionNumber,
01820                               IN ULONG PartitionType)
01821 {
01822     PIRP Irp;
01823     KEVENT Event;
01824     IO_STATUS_BLOCK IoStatusBlock;
01825     NTSTATUS Status;
01826     LARGE_INTEGER Offset, VolumeOffset;
01827     PUCHAR Buffer = NULL;
01828     ULONG BufferSize;
01829     ULONG i = 0;
01830     ULONG Entry;
01831     PPARTITION_DESCRIPTOR PartitionDescriptor;
01832     BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE;
01833     PVOID MbrBuffer;
01834     PIO_STACK_LOCATION IoStackLocation;
01835     VolumeOffset.QuadPart = Offset.QuadPart = 0;
01836     PAGED_CODE();
01837 
01838     /* Normalize the buffer size */
01839     BufferSize = max(512, SectorSize);
01840 
01841     /* Check for EZ Drive */
01842     HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer);
01843     if (MbrBuffer)
01844     {
01845         /* EZ Drive found, bias the offset */
01846         IsEzDrive = TRUE;
01847         ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
01848         Offset.QuadPart = 512;
01849     }
01850 
01851     /* Allocate our partition buffer */
01852     Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
01853     if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
01854 
01855     /* Initialize the event we'll use and loop partitions */
01856     KeInitializeEvent(&Event, NotificationEvent, FALSE);
01857     do
01858     {
01859         /* Reset the event since we reuse it */
01860         KeResetEvent(&Event);
01861 
01862         /* Build the read IRP */
01863         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
01864                                            DeviceObject,
01865                                            Buffer,
01866                                            BufferSize,
01867                                            &Offset,
01868                                            &Event,
01869                                            &IoStatusBlock);
01870         if (!Irp)
01871         {
01872             /* Fail */
01873             Status = STATUS_INSUFFICIENT_RESOURCES;
01874             break;
01875         }
01876 
01877         /* Make sure to disable volume verification */
01878         IoStackLocation = IoGetNextIrpStackLocation(Irp);
01879         IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
01880 
01881         /* Call the driver */
01882         Status = IoCallDriver(DeviceObject, Irp);
01883         if (Status == STATUS_PENDING)
01884         {
01885             /* Wait for completion */
01886             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
01887             Status = IoStatusBlock.Status;
01888         }
01889 
01890         /* Check for failure */
01891         if (!NT_SUCCESS(Status)) break;
01892 
01893         /* If we biased for EZ-Drive, unbias now */
01894         if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
01895 
01896         /* Make sure this is a valid MBR */
01897         if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
01898         {
01899             /* It's not, fail */
01900             Status = STATUS_BAD_MASTER_BOOT_RECORD;
01901             break;
01902         }
01903 
01904         /* Get the partition descriptors and loop them */
01905         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
01906                               &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
01907         for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
01908         {
01909             /* Check if it's unused or a container partition */
01910             if ((PartitionDescriptor->PartitionType ==
01911                  PARTITION_ENTRY_UNUSED) ||
01912                 (IsContainerPartition(PartitionDescriptor->PartitionType)))
01913             {
01914                 /* Go to the next one */
01915                 continue;
01916             }
01917 
01918             /* It's a valid partition, so increase the partition count */
01919             if (++i == PartitionNumber)
01920             {
01921                 /* We found a match, set the type */
01922                 PartitionDescriptor->PartitionType = (UCHAR)PartitionType;
01923 
01924                 /* Reset the reusable event */
01925                 KeResetEvent(&Event);
01926 
01927                 /* Build the write IRP */
01928                 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
01929                                                    DeviceObject,
01930                                                    Buffer,
01931                                                    BufferSize,
01932                                                    &Offset,
01933                                                    &Event,
01934                                                    &IoStatusBlock);
01935                 if (!Irp)
01936                 {
01937                     /* Fail */
01938                     Status = STATUS_INSUFFICIENT_RESOURCES;
01939                     break;
01940                 }
01941 
01942                 /* Disable volume verification */
01943                 IoStackLocation = IoGetNextIrpStackLocation(Irp);
01944                 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
01945 
01946                 /* Call the driver */
01947                 Status = IoCallDriver(DeviceObject, Irp);
01948                 if (Status == STATUS_PENDING)
01949                 {
01950                     /* Wait for completion */
01951                     KeWaitForSingleObject(&Event,
01952                                           Executive,
01953                                           KernelMode,
01954                                           FALSE,
01955                                           NULL);
01956                     Status = IoStatusBlock.Status;
01957                 }
01958 
01959                 /* We're done, break out of the loop */
01960                 break;
01961             }
01962         }
01963 
01964         /* If we looped all the partitions, break out */
01965         if (Entry <= NUM_PARTITION_TABLE_ENTRIES) break;
01966 
01967         /* Nothing found yet, get the partition array again */
01968         PartitionDescriptor = (PPARTITION_DESCRIPTOR)
01969                                &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
01970         for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
01971         {
01972             /* Check if this was a container partition (we skipped these) */
01973             if (IsContainerPartition(PartitionDescriptor->PartitionType))
01974             {
01975                 /* Update the partition offset */
01976                 Offset.QuadPart = VolumeOffset.QuadPart +
01977                                   GET_STARTING_SECTOR(PartitionDescriptor) *
01978                                   SectorSize;
01979 
01980                 /* If this was the primary partition, update the volume too */
01981                 if (IsPrimary) VolumeOffset = Offset;
01982                 break;
01983             }
01984         }
01985 
01986         /* Check if we already searched all the partitions */
01987         if (Entry > NUM_PARTITION_TABLE_ENTRIES)
01988         {
01989             /* Then we failed to find a good MBR */
01990             Status = STATUS_BAD_MASTER_BOOT_RECORD;
01991             break;
01992         }
01993 
01994         /* Loop the next partitions, which are not primary anymore */
01995         IsPrimary = FALSE;
01996     } while (i < PartitionNumber);
01997 
01998     /* Everything done, cleanup */
01999     if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
02000     return Status;
02001 }
02002 
02003 NTSTATUS
02004 FASTCALL
02005 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
02006                           IN ULONG SectorSize,
02007                           IN ULONG SectorsPerTrack,
02008                           IN ULONG NumberOfHeads,
02009                           IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
02010 {
02011     KEVENT Event;
02012     IO_STATUS_BLOCK IoStatusBlock;
02013     PIRP Irp;
02014     NTSTATUS Status = STATUS_SUCCESS;
02015     ULONG BufferSize;
02016     PUSHORT Buffer;
02017     PPTE Entry;
02018     PPARTITION_TABLE PartitionTable;
02019     LARGE_INTEGER Offset, NextOffset, ExtendedOffset, SectorOffset;
02020     LARGE_INTEGER StartOffset, PartitionLength;
02021     ULONG i, j;
02022     CCHAR k;
02023     BOOLEAN IsEzDrive = FALSE, IsSuperFloppy = FALSE, DoRewrite = FALSE, IsMbr;
02024     ULONG ConventionalCylinders;
02025     LONGLONG DiskSize;
02026     PDISK_LAYOUT DiskLayout = (PDISK_LAYOUT)PartitionBuffer;
02027     PVOID MbrBuffer;
02028     UCHAR PartitionType;
02029     PIO_STACK_LOCATION IoStackLocation;
02030     PPARTITION_INFORMATION PartitionInfo = PartitionBuffer->PartitionEntry;
02031     PPARTITION_INFORMATION TableEntry;
02032     ExtendedOffset.QuadPart = NextOffset.QuadPart = Offset.QuadPart = 0;
02033     PAGED_CODE();
02034 
02035     /* Normalize the buffer size */
02036     BufferSize = max(512, SectorSize);
02037 
02038     /* Get the partial drive geometry */
02039     xHalGetPartialGeometry(DeviceObject, &ConventionalCylinders, &DiskSize);
02040 
02041     /* Check for EZ Drive */
02042     HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer);
02043     if (MbrBuffer)
02044     {
02045         /* EZ Drive found, bias the offset */
02046         IsEzDrive = TRUE;
02047         ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
02048         Offset.QuadPart = 512;
02049     }
02050 
02051     /* Get the number of bits to shift to multiply by the sector size */
02052     for (k = 0; k < 32; k++) if ((SectorSize >> k) == 1) break;
02053 
02054     /* Check if there's only one partition */
02055     if (PartitionBuffer->PartitionCount == 1)
02056     {
02057         /* Check if it has no starting offset or hidden sectors */
02058         if (!(PartitionInfo->StartingOffset.QuadPart) &&
02059             !(PartitionInfo->HiddenSectors))
02060         {
02061             /* Then it's a super floppy */
02062             IsSuperFloppy = TRUE;
02063 
02064             /* Which also means it must be non-bootable FAT-16 */
02065             if ((PartitionInfo->PartitionNumber) ||
02066                 (PartitionInfo->PartitionType != PARTITION_FAT_16) ||
02067                 (PartitionInfo->BootIndicator))
02068             {
02069                 /* It's not, so we fail */
02070                 return STATUS_INVALID_PARAMETER;
02071             }
02072 
02073             /* Check if it needs a rewrite, and disable EZ drive for sure */
02074             if (PartitionInfo->RewritePartition) DoRewrite = TRUE;
02075             IsEzDrive = FALSE;
02076         }
02077     }
02078 
02079     /* Count the number of partition tables */
02080     DiskLayout->TableCount = (PartitionBuffer->PartitionCount + 4 - 1) / 4;
02081 
02082     /* Allocate our partition buffer */
02083     Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
02084     if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
02085 
02086     /* Loop the entries */
02087     Entry = (PPTE)&Buffer[PARTITION_TABLE_OFFSET];
02088     for (i = 0; i < DiskLayout->TableCount; i++)
02089     {
02090         /* Set if this is the MBR partition */
02091         IsMbr= (BOOLEAN)!i;
02092 
02093         /* Initialize th event */
02094         KeInitializeEvent(&Event, NotificationEvent, FALSE);
02095 
02096         /* Build the read IRP */
02097         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
02098                                            DeviceObject,
02099                                            Buffer,
02100                                            BufferSize,
02101                                            &Offset,
02102                                            &Event,
02103                                            &IoStatusBlock);
02104         if (!Irp)
02105         {
02106             /* Fail */
02107             Status = STATUS_INSUFFICIENT_RESOURCES;
02108             break;
02109         }
02110 
02111         /* Make sure to disable volume verification */
02112         IoStackLocation = IoGetNextIrpStackLocation(Irp);
02113         IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
02114 
02115         /* Call the driver */
02116         Status = IoCallDriver(DeviceObject, Irp);
02117         if (Status == STATUS_PENDING)
02118         {
02119             /* Wait for completion */
02120             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
02121             Status = IoStatusBlock.Status;
02122         }
02123 
02124         /* Check for failure */
02125         if (!NT_SUCCESS(Status)) break;
02126 
02127         /* If we biased for EZ-Drive, unbias now */
02128         if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
02129 
02130         /* Check if this is a normal disk */
02131         if (!IsSuperFloppy)
02132         {
02133             /* Set the boot record signature */
02134             Buffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE;
02135 
02136             /* By default, don't require a rewrite */
02137             DoRewrite = FALSE;
02138 
02139             /* Check if we don't have an offset */
02140             if (!Offset.QuadPart)
02141             {
02142                 /* Check if the signature doesn't match */
02143                 if (((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] !=
02144                     PartitionBuffer->Signature)
02145                 {
02146                     /* Then write the signature and now w need a rewrite */
02147                     ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] =
02148                         PartitionBuffer->Signature;
02149                     DoRewrite = TRUE;
02150                 }
02151             }
02152 
02153             /* Loop the partition table entries */
02154             PartitionTable = &DiskLayout->PartitionTable[i];
02155             for (j = 0; j < 4; j++)
02156             {
02157                 /* Get the current entry and type */
02158                 TableEntry = &PartitionTable->PartitionEntry[j];
02159                 PartitionType = TableEntry->PartitionType;
02160 
02161                 /* Check if the entry needs a rewrite */
02162                 if (TableEntry->RewritePartition)
02163                 {
02164                     /* Then we need one too */
02165                     DoRewrite = TRUE;
02166 
02167                     /* Save the type and if it's a bootable partition */
02168                     Entry[j].PartitionType = TableEntry->PartitionType;
02169                     Entry[j].ActiveFlag = TableEntry->BootIndicator ? 0x80 : 0;
02170 
02171                     /* Make sure it's used */
02172                     if (PartitionType != PARTITION_ENTRY_UNUSED)
02173                     {
02174                         /* Make sure it's not a container (unless primary) */
02175                         if ((IsMbr) || !(IsContainerPartition(PartitionType)))
02176                         {
02177                             /* Use the partition offset */
02178                             StartOffset.QuadPart = Offset.QuadPart;
02179                         }
02180                         else
02181                         {
02182                             /* Use the extended logical partition offset */
02183                             StartOffset.QuadPart = ExtendedOffset.QuadPart;
02184                         }
02185 
02186                         /* Set the sector offset */
02187                         SectorOffset.QuadPart = TableEntry->
02188                                                 StartingOffset.QuadPart -
02189                                                 StartOffset.QuadPart;
02190 
02191                         /* Now calculate the starting sector */
02192                         StartOffset.QuadPart = SectorOffset.QuadPart >> k;
02193                         Entry[j].StartingSector = StartOffset.LowPart;
02194 
02195                         /* As well as the length */
02196                         PartitionLength.QuadPart = TableEntry->PartitionLength.
02197                                                    QuadPart >> k;
02198                         Entry[j].PartitionLength = PartitionLength.LowPart;
02199 
02200                         /* Calculate the CHS values */
02201                         HalpCalculateChsValues(&TableEntry->StartingOffset,
02202                                                &TableEntry->PartitionLength,
02203                                                k,
02204                                                SectorsPerTrack,
02205                                                NumberOfHeads,
02206                                                ConventionalCylinders,
02207                                                (PPARTITION_DESCRIPTOR)
02208                                                &Entry[j]);
02209                     }
02210                     else
02211                     {
02212                         /* Otherwise set up an empty entry */
02213                         Entry[j].StartingSector = 0;
02214                         Entry[j].PartitionLength = 0;
02215                         Entry[j].StartingTrack = 0;
02216                         Entry[j].EndingTrack = 0;
02217                         Entry[j].StartingCylinder = 0;
02218                         Entry[j].EndingCylinder = 0;
02219                     }
02220                 }
02221 
02222                 /* Check if this is a container partition */
02223                 if (IsContainerPartition(PartitionType))
02224                 {
02225                     /* Then update the offset to use */
02226                     NextOffset = TableEntry->StartingOffset;
02227                 }
02228             }
02229         }
02230 
02231         /* Check if we need to write back the buffer */
02232         if (DoRewrite)
02233         {
02234             /* We don't need to do this again */
02235             DoRewrite = FALSE;
02236 
02237             /* Initialize the event */
02238             KeInitializeEvent(&Event, NotificationEvent, FALSE);
02239 
02240             /* If we unbiased for EZ-Drive, rebias now */
02241             if ((IsEzDrive) && !(Offset.QuadPart)) Offset.QuadPart = 512;
02242 
02243             /* Build the write IRP */
02244             Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
02245                                                DeviceObject,
02246                                                Buffer,
02247                                                BufferSize,
02248                                                &Offset,
02249                                                &Event,
02250                                                &IoStatusBlock);
02251             if (!Irp)
02252             {
02253                 /* Fail */
02254                 Status = STATUS_INSUFFICIENT_RESOURCES;
02255                 break;
02256             }
02257 
02258             /* Make sure to disable volume verification */
02259             IoStackLocation = IoGetNextIrpStackLocation(Irp);
02260             IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
02261 
02262             /* Call the driver */
02263             Status = IoCallDriver(DeviceObject, Irp);
02264             if (Status == STATUS_PENDING)
02265             {
02266                 /* Wait for completion */
02267                 KeWaitForSingleObject(&Event,
02268                                       Executive,
02269                                       KernelMode,
02270                                       FALSE,
02271                                       NULL);
02272                 Status = IoStatusBlock.Status;
02273             }
02274 
02275             /* Check for failure */
02276             if (!NT_SUCCESS(Status)) break;
02277 
02278             /* If we biased for EZ-Drive, unbias now */
02279             if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
02280         }
02281 
02282         /* Update the partition offset and set the extended offset if needed */
02283         Offset = NextOffset;
02284         if (IsMbr) ExtendedOffset = NextOffset;
02285     }
02286 
02287     /* If we had a buffer, free it, then return status */
02288     if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
02289     return Status;
02290 }
02291 
02292 /* PUBLIC FUNCTIONS **********************************************************/
02293 
02294 /*
02295  * @implemented
02296  */
02297 VOID
02298 FASTCALL
02299 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
02300               IN ULONG SectorSize,
02301               IN ULONG MbrTypeIdentifier,
02302               OUT PVOID *MbrBuffer)
02303 {
02304     HALDISPATCH->HalExamineMBR(DeviceObject,
02305                                SectorSize,
02306                                MbrTypeIdentifier,
02307                                MbrBuffer);
02308 }
02309 
02310 /*
02311  * @implemented
02312  */
02313 NTSTATUS
02314 FASTCALL
02315 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
02316                      IN ULONG SectorSize,
02317                      IN BOOLEAN ReturnRecognizedPartitions,
02318                      IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
02319 {
02320     return HALDISPATCH->HalIoReadPartitionTable(DeviceObject,
02321                                                 SectorSize,
02322                                                 ReturnRecognizedPartitions,
02323                                                 PartitionBuffer);
02324 }
02325 
02326 /*
02327  * @implemented
02328  */
02329 NTSTATUS
02330 FASTCALL
02331 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
02332                           IN ULONG SectorSize,
02333                           IN ULONG PartitionNumber,
02334                           IN ULONG PartitionType)
02335 {
02336     return HALDISPATCH->HalIoSetPartitionInformation(DeviceObject,
02337                                                      SectorSize,
02338                                                      PartitionNumber,
02339                                                      PartitionType);
02340 }
02341 
02342 /*
02343  * @implemented
02344  */
02345 NTSTATUS
02346 FASTCALL
02347 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
02348                       IN ULONG SectorSize,
02349                       IN ULONG SectorsPerTrack,
02350                       IN ULONG NumberOfHeads,
02351                       IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
02352 {
02353     return HALDISPATCH->HalIoWritePartitionTable(DeviceObject,
02354                                                  SectorSize,
02355                                                  SectorsPerTrack,
02356                                                  NumberOfHeads,
02357                                                  PartitionBuffer);
02358 }
02359 
02360 /*
02361  * @implemented
02362  */
02363 VOID
02364 FASTCALL
02365 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
02366                      IN PSTRING NtDeviceName,
02367                      OUT PUCHAR NtSystemPath,
02368                      OUT PSTRING NtSystemPathString)
02369 {
02370     HALDISPATCH->HalIoAssignDriveLetters(LoaderBlock,
02371                                          NtDeviceName,
02372                                          NtSystemPath,
02373                                          NtSystemPathString);
02374 }
02375 
02376 /* EOF */

Generated on Mon May 28 2012 04:37:07 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.