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

arcname.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/io/iomgr/arcname.c
00005 * PURPOSE:         ARC Path Initialization Functions
00006 * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007 *                  Eric Kohl
00008 *                  Pierre Schweitzer (pierre.schweitzer@reactos.org)
00009 */
00010 
00011 /* INCLUDES ******************************************************************/
00012 
00013 #include <ntoskrnl.h>
00014 #define NDEBUG
00015 #include <debug.h>
00016 
00017 /* GLOBALS *******************************************************************/
00018 
00019 UNICODE_STRING IoArcHalDeviceName, IoArcBootDeviceName;
00020 PCHAR IoLoaderArcBootDeviceName;
00021 extern BOOLEAN IoRemoteBootClient;
00022 
00023 /* FUNCTIONS *****************************************************************/
00024 
00025 NTSTATUS
00026 INIT_FUNCTION
00027 NTAPI
00028 IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock
00029 );
00030 
00031 NTSTATUS
00032 INIT_FUNCTION
00033 NTAPI
00034 IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
00035                       IN BOOLEAN SingleDisk,
00036                       IN PBOOLEAN FoundBoot
00037 );
00038 
00039 NTSTATUS
00040 INIT_FUNCTION
00041 NTAPI
00042 IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
00043 {
00044     SIZE_T Length;
00045     NTSTATUS Status;
00046     CHAR Buffer[128];
00047     BOOLEAN SingleDisk;
00048     BOOLEAN FoundBoot = FALSE;
00049     UNICODE_STRING SystemDevice, LoaderPathNameW, BootDeviceName;
00050     PARC_DISK_INFORMATION ArcDiskInfo = LoaderBlock->ArcDiskInformation;
00051     ANSI_STRING ArcSystemString, ArcString, LanmanRedirector, LoaderPathNameA;
00052 
00053     /* Check if we only have one disk on the machine */
00054     SingleDisk = ArcDiskInfo->DiskSignatureListHead.Flink->Flink ==
00055                  (&ArcDiskInfo->DiskSignatureListHead);
00056 
00057     /* Create the global HAL partition name */
00058     sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcHalDeviceName);
00059     RtlInitAnsiString(&ArcString, Buffer);
00060     RtlAnsiStringToUnicodeString(&IoArcHalDeviceName, &ArcString, TRUE);
00061 
00062     /* Create the global system partition name */
00063     sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
00064     RtlInitAnsiString(&ArcString, Buffer);
00065     RtlAnsiStringToUnicodeString(&IoArcBootDeviceName, &ArcString, TRUE);
00066 
00067     /* Allocate memory for the string */
00068     Length = strlen(LoaderBlock->ArcBootDeviceName) + sizeof(ANSI_NULL);
00069     IoLoaderArcBootDeviceName = ExAllocatePoolWithTag(PagedPool,
00070                                                       Length,
00071                                                       TAG_IO);
00072     if (IoLoaderArcBootDeviceName)
00073     {
00074         /* Copy the name */
00075         RtlCopyMemory(IoLoaderArcBootDeviceName,
00076                       LoaderBlock->ArcBootDeviceName,
00077                       Length);
00078     }
00079 
00080     /* Check if we only found a disk, but we're booting from CD-ROM */
00081     if ((SingleDisk) && strstr(LoaderBlock->ArcBootDeviceName, "cdrom"))
00082     {
00083         /* Then disable single-disk mode, since there's a CD drive out there */
00084         SingleDisk = FALSE;
00085     }
00086 
00087     /* Build the boot strings */
00088     RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
00089 
00090     /* If we are doing remote booting */
00091     if (IoRemoteBootClient)
00092     {
00093         /* Yes, we have found boot device */
00094         FoundBoot = TRUE;
00095 
00096         /* Get NT device name */
00097         RtlInitAnsiString(&LanmanRedirector, "\\Device\\LanmanRedirector");
00098         Status = RtlAnsiStringToUnicodeString(&SystemDevice, &LanmanRedirector, TRUE);
00099         if (!NT_SUCCESS(Status))
00100         {
00101             return Status;
00102         }
00103 
00104         /* Get ARC booting device name (in net(0) something) */
00105         sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
00106         RtlInitAnsiString(&ArcString, Buffer);
00107         Status = RtlAnsiStringToUnicodeString(&BootDeviceName, &ArcString, TRUE);
00108         if (NT_SUCCESS(Status))
00109         {
00110             /* Map ARC to NT name */
00111             IoAssignArcName(&BootDeviceName, &SystemDevice);
00112             RtlFreeUnicodeString(&BootDeviceName);
00113 
00114             /* Now, get loader path name */
00115             RtlInitAnsiString(&LoaderPathNameA, LoaderBlock->NtHalPathName);
00116             Status = RtlAnsiStringToUnicodeString(&LoaderPathNameW, &LoaderPathNameA, TRUE);
00117             if (!NT_SUCCESS(Status))
00118             {
00119                 RtlFreeUnicodeString(&SystemDevice);
00120                 return Status;
00121             }
00122 
00123             /* And set it has system partition */
00124             IopStoreSystemPartitionInformation(&SystemDevice, &LoaderPathNameW);
00125         }
00126 
00127         RtlFreeUnicodeString(&SystemDevice);
00128 
00129         /* Don't quit here, even if everything went fine!
00130          * We need IopCreateArcNamesDisk to properly map
00131          * devices with symlinks.
00132          * It will return success if the mapping process went fine
00133          * even if it didn't find boot device.
00134          * It won't reset boot device finding status as well.
00135          */
00136     }
00137 
00138     /* Loop every disk and try to find boot disk */
00139     Status = IopCreateArcNamesDisk(LoaderBlock, SingleDisk, &FoundBoot);
00140     /* If it succeed but we didn't find boot device, try to browse Cds */
00141     if (NT_SUCCESS(Status) && !FoundBoot)
00142     {
00143         Status = IopCreateArcNamesCd(LoaderBlock);
00144     }
00145 
00146     /* Return success */
00147     return Status;
00148 }
00149 
00150 NTSTATUS
00151 INIT_FUNCTION
00152 NTAPI
00153 IopCreateArcNamesCd(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
00154 {
00155     PIRP Irp;
00156     KEVENT Event;
00157     NTSTATUS Status;
00158     PLIST_ENTRY NextEntry;
00159     PFILE_OBJECT FileObject;
00160     PDEVICE_OBJECT DeviceObject;
00161     LARGE_INTEGER StartingOffset;
00162     IO_STATUS_BLOCK IoStatusBlock;
00163     PULONG PartitionBuffer = NULL;
00164     CHAR Buffer[128], ArcBuffer[128];
00165     BOOLEAN NotEnabledPresent = FALSE;
00166     STORAGE_DEVICE_NUMBER DeviceNumber;
00167     ANSI_STRING DeviceStringA, ArcNameStringA;
00168     PWSTR SymbolicLinkList, lSymbolicLinkList;
00169     PARC_DISK_SIGNATURE ArcDiskSignature = NULL;
00170     UNICODE_STRING DeviceStringW, ArcNameStringW;
00171     ULONG DiskNumber, CdRomCount, CheckSum, i, EnabledDisks = 0;
00172     PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation;
00173 
00174     /* Get all the Cds present in the system */
00175     CdRomCount = IoGetConfigurationInformation()->CdRomCount;
00176 
00177     /* Get enabled Cds and check if result matches
00178      * For the record, enabled Cds (or even disk) are Cds/disks
00179      * that have been successfully handled by MountMgr driver
00180      * and that already own their device name. This is the "new" way
00181      * to handle them, that came with NT5.
00182      * Currently, Windows 2003 provides an arc names creation based
00183      * on both enabled drives and not enabled drives (lack from
00184      * the driver).
00185      * Given the current ReactOS state, that's good for us.
00186      * To sum up, this is NOT a hack or whatsoever.
00187      */
00188     Status = IopFetchConfigurationInformation(&SymbolicLinkList,
00189                                               GUID_DEVINTERFACE_CDROM,
00190                                               CdRomCount,
00191                                               &EnabledDisks);
00192     if (!NT_SUCCESS(Status))
00193     {
00194         NotEnabledPresent = TRUE;
00195     }
00196     /* Save symbolic link list address in order to free it after */
00197     lSymbolicLinkList = SymbolicLinkList;
00198     /* For the moment, we won't fail */
00199     Status = STATUS_SUCCESS;
00200 
00201     /* Browse all the ARC devices trying to find the one matching boot device */
00202     for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
00203          NextEntry != &ArcDiskInformation->DiskSignatureListHead;
00204          NextEntry = NextEntry->Flink)
00205     {
00206         ArcDiskSignature = CONTAINING_RECORD(NextEntry,
00207                                              ARC_DISK_SIGNATURE,
00208                                              ListEntry);
00209 
00210         if (strcmp(LoaderBlock->ArcBootDeviceName, ArcDiskSignature->ArcName) == 0)
00211         {
00212             break;
00213         }
00214 
00215         ArcDiskSignature = NULL;
00216     }
00217 
00218     /* Not found... Not booting from a Cd */
00219     if (!ArcDiskSignature)
00220     {
00221         DPRINT("Failed finding a cd that could match current boot device\n");
00222         goto Cleanup;
00223     }
00224 
00225     /* Allocate needed space for reading Cd */
00226     PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 2048, TAG_IO);
00227     if (!PartitionBuffer)
00228     {
00229         DPRINT("Failed allocating resources!\n");
00230         /* Here, we fail, BUT we return success, some Microsoft joke */
00231         goto Cleanup;
00232     }
00233 
00234     /* If we have more enabled Cds, take that into account */
00235     if (EnabledDisks > CdRomCount)
00236     {
00237         CdRomCount = EnabledDisks;
00238     }
00239 
00240     /* If we'll have to browse for none enabled Cds, fix higher count */
00241     if (NotEnabledPresent && !EnabledDisks)
00242     {
00243         CdRomCount += 5;
00244     }
00245 
00246     /* Finally, if in spite of all that work, we still don't have Cds, leave */
00247     if (!CdRomCount)
00248     {
00249         goto Cleanup;
00250     }
00251 
00252     /* Start browsing Cds */
00253     for (DiskNumber = 0, EnabledDisks = 0; DiskNumber < CdRomCount; DiskNumber++)
00254     {
00255         /* Check if we have an enabled disk */
00256         if (SymbolicLinkList && *SymbolicLinkList != UNICODE_NULL)
00257         {
00258             /* Create its device name using first symbolic link */
00259             RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList);
00260             /* Then, update symbolic links list */
00261             lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
00262 
00263             /* Get its associated device object and file object */
00264             Status = IoGetDeviceObjectPointer(&DeviceStringW,
00265                                               FILE_READ_ATTRIBUTES,
00266                                               &FileObject,
00267                                               &DeviceObject);
00268             /* Failure? Good bye! */
00269             if (!NT_SUCCESS(Status))
00270             {
00271                 goto Cleanup;
00272             }
00273 
00274             /* Now, we'll ask the device its device number */
00275             Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
00276                                                 DeviceObject,
00277                                                 NULL,
00278                                                 0,
00279                                                 &DeviceNumber,
00280                                                 sizeof(STORAGE_DEVICE_NUMBER),
00281                                                 FALSE,
00282                                                 &Event,
00283                                                 &IoStatusBlock);
00284             /* Failure? Good bye! */
00285             if (!Irp)
00286             {
00287                 /* Dereference file object before leaving */
00288                 ObDereferenceObject(FileObject);
00289                 Status = STATUS_INSUFFICIENT_RESOURCES;
00290                 goto Cleanup;
00291             }
00292 
00293             /* Call the driver, and wait for it if needed */
00294             KeInitializeEvent(&Event, NotificationEvent, FALSE);
00295             Status = IoCallDriver(DeviceObject, Irp);
00296             if (Status == STATUS_PENDING)
00297             {
00298                 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
00299                 Status = IoStatusBlock.Status;
00300             }
00301             if (!NT_SUCCESS(Status))
00302             {
00303                 ObDereferenceObject(FileObject);
00304                 goto Cleanup;
00305             }
00306 
00307             /* Finally, build proper device name */
00308             sprintf(Buffer, "\\Device\\CdRom%lu", DeviceNumber.DeviceNumber);
00309             RtlInitAnsiString(&DeviceStringA, Buffer);
00310             Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
00311             if (!NT_SUCCESS(Status))
00312             {
00313                 ObDereferenceObject(FileObject);
00314                 goto Cleanup;
00315             }
00316         }
00317         else
00318         {
00319             /* Create device name for the cd */
00320             sprintf(Buffer, "\\Device\\CdRom%lu", EnabledDisks++);
00321             RtlInitAnsiString(&DeviceStringA, Buffer);
00322             Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
00323             if (!NT_SUCCESS(Status))
00324             {
00325                 goto Cleanup;
00326             }
00327 
00328             /* Get its device object */
00329             Status = IoGetDeviceObjectPointer(&DeviceStringW,
00330                                               FILE_READ_ATTRIBUTES,
00331                                               &FileObject,
00332                                               &DeviceObject);
00333             if (!NT_SUCCESS(Status))
00334             {
00335                 RtlFreeUnicodeString(&DeviceStringW);
00336                 goto Cleanup;
00337             }
00338         }
00339 
00340         /* Initiate data for reading cd and compute checksum */
00341         StartingOffset.QuadPart = 0x8000;
00342         CheckSum = 0;
00343         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
00344                                            DeviceObject,
00345                                            PartitionBuffer,
00346                                            2048,
00347                                            &StartingOffset,
00348                                            &Event,
00349                                            &IoStatusBlock);
00350         if (Irp)
00351         {
00352             /* Call the driver, and wait for it if needed */
00353             KeInitializeEvent(&Event, NotificationEvent, FALSE);
00354             Status = IoCallDriver(DeviceObject, Irp);
00355             if (Status == STATUS_PENDING)
00356             {
00357                 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
00358                 Status = IoStatusBlock.Status;
00359             }
00360 
00361             /* Reading succeed, compute checksum by adding data, 2048 bytes checksum */
00362             if (NT_SUCCESS(Status))
00363             {
00364                 for (i = 0; i < 2048 / sizeof(ULONG); i++)
00365                 {
00366                     CheckSum += PartitionBuffer[i];
00367                 }
00368             }
00369         }
00370 
00371         /* Dereference file object */
00372         ObDereferenceObject(FileObject);
00373 
00374         /* If checksums are matching, we have the proper cd */
00375         if (CheckSum + ArcDiskSignature->CheckSum == 0)
00376         {
00377             /* Create ARC name */
00378             sprintf(ArcBuffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
00379             RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
00380             Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
00381             if (NT_SUCCESS(Status))
00382             {
00383                 /* Create symbolic link */
00384                 IoAssignArcName(&ArcNameStringW, &DeviceStringW);
00385                 RtlFreeUnicodeString(&ArcNameStringW);
00386                 DPRINT1("Boot device found\n");
00387             }
00388 
00389             /* And quit, whatever happens */
00390             RtlFreeUnicodeString(&DeviceStringW);
00391             goto Cleanup;
00392         }
00393 
00394         /* Free string before trying another disk */
00395         RtlFreeUnicodeString(&DeviceStringW);
00396     }
00397 
00398 Cleanup:
00399     if (PartitionBuffer)
00400     {
00401         ExFreePoolWithTag(PartitionBuffer, TAG_IO);
00402     }
00403 
00404     if (SymbolicLinkList)
00405     {
00406         ExFreePool(SymbolicLinkList);
00407     }
00408 
00409     return Status;
00410 }
00411 
00412 NTSTATUS
00413 INIT_FUNCTION
00414 NTAPI
00415 IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
00416                       IN BOOLEAN SingleDisk,
00417                       IN PBOOLEAN FoundBoot)
00418 {
00419     PIRP Irp;
00420     PVOID Data;
00421     KEVENT Event;
00422     NTSTATUS Status;
00423     PLIST_ENTRY NextEntry;
00424     PFILE_OBJECT FileObject;
00425     DISK_GEOMETRY DiskGeometry;
00426     PDEVICE_OBJECT DeviceObject;
00427     LARGE_INTEGER StartingOffset;
00428     PULONG PartitionBuffer = NULL;
00429     IO_STATUS_BLOCK IoStatusBlock;
00430     CHAR Buffer[128], ArcBuffer[128];
00431     BOOLEAN NotEnabledPresent = FALSE;
00432     STORAGE_DEVICE_NUMBER DeviceNumber;
00433     PARC_DISK_SIGNATURE ArcDiskSignature;
00434     PWSTR SymbolicLinkList, lSymbolicLinkList;
00435     PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL;
00436     UNICODE_STRING DeviceStringW, ArcNameStringW, HalPathStringW;
00437     ULONG DiskNumber, DiskCount, CheckSum, i, Signature, EnabledDisks = 0;
00438     PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation;
00439     ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA, HalPathStringA;
00440 
00441     /* Initialise device number */
00442     DeviceNumber.DeviceNumber = ULONG_MAX;
00443     /* Get all the disks present in the system */
00444     DiskCount = IoGetConfigurationInformation()->DiskCount;
00445 
00446     /* Get enabled disks and check if result matches */
00447     Status = IopFetchConfigurationInformation(&SymbolicLinkList,
00448                                               GUID_DEVINTERFACE_DISK,
00449                                               DiskCount,
00450                                               &EnabledDisks);
00451     if (!NT_SUCCESS(Status))
00452     {
00453         NotEnabledPresent = TRUE;
00454     }
00455 
00456     /* Save symbolic link list address in order to free it after */
00457     lSymbolicLinkList = SymbolicLinkList;
00458 
00459     /* Build the boot strings */
00460     RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName);
00461     RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
00462 
00463     /* If we have more enabled disks, take that into account */
00464     if (EnabledDisks > DiskCount)
00465     {
00466         DiskCount = EnabledDisks;
00467     }
00468 
00469     /* If we'll have to browse for none enabled disks, fix higher count */
00470     if (NotEnabledPresent && !EnabledDisks)
00471     {
00472         DiskCount += 20;
00473     }
00474 
00475     /* Finally, if in spite of all that work, we still don't have disks, leave */
00476     if (!DiskCount)
00477     {
00478         goto Cleanup;
00479     }
00480 
00481     /* Start browsing disks */
00482     for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++)
00483     {
00484         /* Check if we have an enabled disk */
00485         if (lSymbolicLinkList && *lSymbolicLinkList != UNICODE_NULL)
00486         {
00487             /* Create its device name using first symbolic link */
00488             RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList);
00489             /* Then, update symbolic links list */
00490             lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
00491 
00492             /* Get its associated device object and file object */
00493             Status = IoGetDeviceObjectPointer(&DeviceStringW,
00494                                               FILE_READ_ATTRIBUTES,
00495                                               &FileObject,
00496                                               &DeviceObject);
00497             if (NT_SUCCESS(Status))
00498             {
00499                 /* Now, we'll ask the device its device number */
00500                 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
00501                                                     DeviceObject,
00502                                                     NULL,
00503                                                     0,
00504                                                     &DeviceNumber,
00505                                                     sizeof(STORAGE_DEVICE_NUMBER),
00506                                                     FALSE,
00507                                                     &Event,
00508                                                     &IoStatusBlock);
00509                 /* Missing resources is a shame... No need to go farther */
00510                 if (!Irp)
00511                 {
00512                     ObDereferenceObject(FileObject);
00513                     Status = STATUS_INSUFFICIENT_RESOURCES;
00514                     goto Cleanup;
00515                 }
00516 
00517                 /* Call the driver, and wait for it if needed */
00518                 KeInitializeEvent(&Event, NotificationEvent, FALSE);
00519                 Status = IoCallDriver(DeviceObject, Irp);
00520                 if (Status == STATUS_PENDING)
00521                 {
00522                     KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
00523                     Status = IoStatusBlock.Status;
00524                 }
00525 
00526                 /* If we didn't get the appriopriate data, just skip that disk */
00527                 if (!NT_SUCCESS(Status))
00528                 {
00529                    ObDereferenceObject(FileObject);
00530                    continue;
00531                 }
00532             }
00533 
00534             /* End of enabled disks enumeration */
00535             if (NotEnabledPresent && *lSymbolicLinkList == UNICODE_NULL)
00536             {
00537                 /* No enabled disk worked, reset field */
00538                 if (DeviceNumber.DeviceNumber == ULONG_MAX)
00539                 {
00540                     DeviceNumber.DeviceNumber = 0;
00541                 }
00542 
00543                 /* Update disk number to enable the following not enabled disks */
00544                 if (DeviceNumber.DeviceNumber > DiskNumber)
00545                 {
00546                     DiskNumber = DeviceNumber.DeviceNumber;
00547                 }
00548 
00549                 /* Increase a bit more */
00550                 DiskCount = DiskNumber + 20;
00551             }
00552         }
00553         else
00554         {
00555             /* Create device name for the disk */
00556             sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber);
00557             RtlInitAnsiString(&DeviceStringA, Buffer);
00558             Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
00559             if (!NT_SUCCESS(Status))
00560             {
00561                 goto Cleanup;
00562             }
00563 
00564             /* Get its device object */
00565             Status = IoGetDeviceObjectPointer(&DeviceStringW,
00566                                               FILE_READ_ATTRIBUTES,
00567                                               &FileObject,
00568                                               &DeviceObject);
00569 
00570             RtlFreeUnicodeString(&DeviceStringW);
00571             /* This is a security measure, to ensure DiskNumber will be used */
00572             DeviceNumber.DeviceNumber = ULONG_MAX;
00573         }
00574 
00575         /* Something failed somewhere earlier, just skip the disk */
00576         if (!NT_SUCCESS(Status))
00577         {
00578             continue;
00579         }
00580 
00581         /* Let's ask the disk for its geometry */
00582         Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
00583                                             DeviceObject,
00584                                             NULL,
00585                                             0,
00586                                             &DiskGeometry,
00587                                             sizeof(DISK_GEOMETRY),
00588                                             FALSE,
00589                                             &Event,
00590                                             &IoStatusBlock);
00591         /* Missing resources is a shame... No need to go farther */
00592         if (!Irp)
00593         {
00594             ObDereferenceObject(FileObject);
00595             Status = STATUS_INSUFFICIENT_RESOURCES;
00596             goto Cleanup;
00597         }
00598 
00599         /* Call the driver, and wait for it if needed */
00600         KeInitializeEvent(&Event, NotificationEvent, FALSE);
00601         Status = IoCallDriver(DeviceObject, Irp);
00602         if (Status == STATUS_PENDING)
00603         {
00604             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
00605             Status = IoStatusBlock.Status;
00606         }
00607         /* Failure, skip disk */
00608         if (!NT_SUCCESS(Status))
00609         {
00610             ObDereferenceObject(FileObject);
00611             continue;
00612         }
00613 
00614         /* Read the partition table */
00615         Status = IoReadPartitionTableEx(DeviceObject,
00616                                         &DriveLayout);
00617         if (!NT_SUCCESS(Status))
00618         {
00619             ObDereferenceObject(FileObject);
00620             continue;
00621         }
00622 
00623         /* Ensure we have at least 512 bytes per sector */
00624         if (DiskGeometry.BytesPerSector < 512)
00625         {
00626             DiskGeometry.BytesPerSector = 512;
00627         }
00628 
00629         /* Check MBR type against EZ Drive type */
00630         StartingOffset.QuadPart = 0;
00631         HalExamineMBR(DeviceObject, DiskGeometry.BytesPerSector, 0x55, &Data);
00632         if (Data)
00633         {
00634             /* If MBR is of the EZ Drive type, we'll read after it */
00635             StartingOffset.QuadPart = DiskGeometry.BytesPerSector;
00636             ExFreePool(Data);
00637         }
00638 
00639         /* Allocate for reading enough data for checksum */
00640         PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskGeometry.BytesPerSector, TAG_IO);
00641         if (!PartitionBuffer)
00642         {
00643             ObDereferenceObject(FileObject);
00644             Status = STATUS_INSUFFICIENT_RESOURCES;
00645             goto Cleanup;
00646         }
00647 
00648         /* Read a sector for computing checksum */
00649         Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
00650                                            DeviceObject,
00651                                            PartitionBuffer,
00652                                            DiskGeometry.BytesPerSector,
00653                                            &StartingOffset,
00654                                            &Event,
00655                                            &IoStatusBlock);
00656         if (!Irp)
00657         {
00658             ObDereferenceObject(FileObject);
00659             Status = STATUS_INSUFFICIENT_RESOURCES;
00660             goto Cleanup;
00661         }
00662 
00663         /* Call the driver to perform reading */
00664         KeInitializeEvent(&Event, NotificationEvent, FALSE);
00665         Status = IoCallDriver(DeviceObject, Irp);
00666         if (Status == STATUS_PENDING)
00667         {
00668             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
00669             Status = IoStatusBlock.Status;
00670         }
00671         if (!NT_SUCCESS(Status))
00672         {
00673             ExFreePool(DriveLayout);
00674             ExFreePoolWithTag(PartitionBuffer, TAG_IO);
00675             ObDereferenceObject(FileObject);
00676             continue;
00677         }
00678 
00679         ObDereferenceObject(FileObject);
00680 
00681         /* Calculate checksum, that's an easy computation, just adds read data */
00682         for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG) ; i++)
00683         {
00684             CheckSum += PartitionBuffer[i];
00685         }
00686 
00687         /* Browse each ARC disk */
00688         for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
00689              NextEntry != &ArcDiskInformation->DiskSignatureListHead;
00690              NextEntry = NextEntry->Flink)
00691         {
00692             ArcDiskSignature = CONTAINING_RECORD(NextEntry,
00693                                                  ARC_DISK_SIGNATURE,
00694                                                  ListEntry);
00695 
00696             /* If they matches, ie
00697              * - There's only one disk for both BIOS and detected/enabled
00698              * - Signatures are matching
00699              * - Checksums are matching
00700              * - This is MBR
00701              */
00702             if (((SingleDisk && DiskCount == 1) ||
00703                 (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature) &&
00704                  (ArcDiskSignature->CheckSum + CheckSum == 0))) &&
00705                 (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR))
00706             {
00707                 /* Create device name */
00708                 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber);
00709                 RtlInitAnsiString(&DeviceStringA, Buffer);
00710                 Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
00711                 if (!NT_SUCCESS(Status))
00712                 {
00713                     goto Cleanup;
00714                 }
00715 
00716                 /* Create ARC name */
00717                 sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName);
00718                 RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
00719                 Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
00720                 if (!NT_SUCCESS(Status))
00721                 {
00722                     RtlFreeUnicodeString(&DeviceStringW);
00723                     goto Cleanup;
00724                 }
00725 
00726                 /* Link both */
00727                 IoAssignArcName(&ArcNameStringW, &DeviceStringW);
00728 
00729                 /* And release resources */
00730                 RtlFreeUnicodeString(&ArcNameStringW);
00731                 RtlFreeUnicodeString(&DeviceStringW);
00732 
00733                 /* Now, browse for every partition */
00734                 for (i = 1; i <= DriveLayout->PartitionCount; i++)
00735                 {
00736                     /* Create device name */
00737                     sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", (DeviceNumber.DeviceNumber != ULONG_MAX) ? DeviceNumber.DeviceNumber : DiskNumber, i);
00738                     RtlInitAnsiString(&DeviceStringA, Buffer);
00739                     Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
00740                     if (!NT_SUCCESS(Status))
00741                     {
00742                         goto Cleanup;
00743                     }
00744 
00745                     /* Create partial ARC name */
00746                     sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, i);
00747                     RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
00748 
00749                     /* Is that boot device? */
00750                     if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE))
00751                     {
00752                         DPRINT("Found boot device\n");
00753                         *FoundBoot = TRUE;
00754                     }
00755 
00756                     /* Is that system partition? */
00757                     if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE))
00758                     {
00759                         /* Create HAL path name */
00760                         RtlInitAnsiString(&HalPathStringA, LoaderBlock->NtHalPathName);
00761                         Status = RtlAnsiStringToUnicodeString(&HalPathStringW, &HalPathStringA, TRUE);
00762                         if (!NT_SUCCESS(Status))
00763                         {
00764                             RtlFreeUnicodeString(&DeviceStringW);
00765                             goto Cleanup;
00766                         }
00767 
00768                         /* Then store those information to registry */
00769                         IopStoreSystemPartitionInformation(&DeviceStringW, &HalPathStringW);
00770                         RtlFreeUnicodeString(&HalPathStringW);
00771                     }
00772 
00773                     /* Create complete ARC name */
00774                     sprintf(ArcBuffer, "\\ArcName\\%spartition(%lu)", ArcDiskSignature->ArcName, i);
00775                     RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
00776                     Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE);
00777                     if (!NT_SUCCESS(Status))
00778                     {
00779                         RtlFreeUnicodeString(&DeviceStringW);
00780                         goto Cleanup;
00781                     }
00782 
00783                     /* Link device name & ARC name */
00784                     IoAssignArcName(&ArcNameStringW, &DeviceStringW);
00785 
00786                     /* Release strings */
00787                     RtlFreeUnicodeString(&ArcNameStringW);
00788                     RtlFreeUnicodeString(&DeviceStringW);
00789                 }
00790             }
00791             else
00792             {
00793                 /* In case there's a valid partition, a matching signature,
00794                    BUT a none matching checksum, or there's a duplicate
00795                    signature, or even worse a virus played with partition
00796                    table */
00797                 if (ArcDiskSignature->Signature == Signature &&
00798                     (ArcDiskSignature->CheckSum + CheckSum != 0) &&
00799                     ArcDiskSignature->ValidPartitionTable)
00800                  {
00801                      DPRINT("Be careful, or you have a duplicate disk signature, or a virus altered your MBR!\n");
00802                  }
00803             }
00804         }
00805 
00806         /* Release memory before jumping to next item */
00807         ExFreePool(DriveLayout);
00808         DriveLayout = NULL;
00809         ExFreePoolWithTag(PartitionBuffer, TAG_IO);
00810         PartitionBuffer = NULL;
00811     }
00812 
00813     Status = STATUS_SUCCESS;
00814 
00815 Cleanup:
00816     if (SymbolicLinkList)
00817     {
00818         ExFreePool(SymbolicLinkList);
00819     }
00820 
00821     if (DriveLayout)
00822     {
00823         ExFreePool(DriveLayout);
00824     }
00825 
00826     if (PartitionBuffer)
00827     {
00828         ExFreePoolWithTag(PartitionBuffer, TAG_IO);
00829     }
00830 
00831     return Status;
00832 }
00833 
00834 NTSTATUS
00835 NTAPI
00836 INIT_FUNCTION
00837 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
00838                       OUT PANSI_STRING NtBootPath)
00839 {
00840     OBJECT_ATTRIBUTES ObjectAttributes;
00841     NTSTATUS Status;
00842     CHAR Buffer[256], AnsiBuffer[256];
00843     WCHAR ArcNameBuffer[64];
00844     ANSI_STRING TargetString, ArcString, TempString;
00845     UNICODE_STRING LinkName, TargetName, ArcName;
00846     HANDLE LinkHandle;
00847 
00848     /* Create the Unicode name for the current ARC boot device */
00849     sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
00850     RtlInitAnsiString(&TargetString, Buffer);
00851     Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE);
00852     if (!NT_SUCCESS(Status)) return FALSE;
00853 
00854     /* Initialize the attributes and open the link */
00855     InitializeObjectAttributes(&ObjectAttributes,
00856                                &TargetName,
00857                                OBJ_CASE_INSENSITIVE,
00858                                NULL,
00859                                NULL);
00860     Status = NtOpenSymbolicLinkObject(&LinkHandle,
00861                                       SYMBOLIC_LINK_ALL_ACCESS,
00862                                       &ObjectAttributes);
00863     if (!NT_SUCCESS(Status))
00864     {
00865         /* We failed, free the string */
00866         RtlFreeUnicodeString(&TargetName);
00867         return FALSE;
00868     }
00869 
00870     /* Query the current \\SystemRoot */
00871     ArcName.Buffer = ArcNameBuffer;
00872     ArcName.Length = 0;
00873     ArcName.MaximumLength = sizeof(ArcNameBuffer);
00874     Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL);
00875     if (!NT_SUCCESS(Status))
00876     {
00877         /* We failed, free the string */
00878         RtlFreeUnicodeString(&TargetName);
00879         return FALSE;
00880     }
00881 
00882     /* Convert it to Ansi */
00883     ArcString.Buffer = AnsiBuffer;
00884     ArcString.Length = 0;
00885     ArcString.MaximumLength = sizeof(AnsiBuffer);
00886     Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE);
00887     AnsiBuffer[ArcString.Length] = ANSI_NULL;
00888 
00889     /* Close the link handle and free the name */
00890     ObCloseHandle(LinkHandle, KernelMode);
00891     RtlFreeUnicodeString(&TargetName);
00892 
00893     /* Setup the system root name again */
00894     RtlInitAnsiString(&TempString, "\\SystemRoot");
00895     Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE);
00896     if (!NT_SUCCESS(Status)) return FALSE;
00897 
00898     /* Open the symbolic link for it */
00899     InitializeObjectAttributes(&ObjectAttributes,
00900                                &LinkName,
00901                                OBJ_CASE_INSENSITIVE,
00902                                NULL,
00903                                NULL);
00904     Status = NtOpenSymbolicLinkObject(&LinkHandle,
00905                                       SYMBOLIC_LINK_ALL_ACCESS,
00906                                       &ObjectAttributes);
00907     if (!NT_SUCCESS(Status)) return FALSE;
00908 
00909     /* Destroy it */
00910     NtMakeTemporaryObject(LinkHandle);
00911     ObCloseHandle(LinkHandle, KernelMode);
00912 
00913     /* Now create the new name for it */
00914     sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName);
00915 
00916     /* Copy it into the passed parameter and null-terminate it */
00917     RtlCopyString(NtBootPath, &ArcString);
00918     Buffer[strlen(Buffer) - 1] = ANSI_NULL;
00919 
00920     /* Setup the Unicode-name for the new symbolic link value */
00921     RtlInitAnsiString(&TargetString, Buffer);
00922     InitializeObjectAttributes(&ObjectAttributes,
00923                                &LinkName,
00924                                OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
00925                                NULL,
00926                                NULL);
00927     Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE);
00928     if (!NT_SUCCESS(Status)) return FALSE;
00929 
00930     /* Create it */
00931     Status = NtCreateSymbolicLinkObject(&LinkHandle,
00932                                         SYMBOLIC_LINK_ALL_ACCESS,
00933                                         &ObjectAttributes,
00934                                         &ArcName);
00935 
00936     /* Free all the strings and close the handle and return success */
00937     RtlFreeUnicodeString(&ArcName);
00938     RtlFreeUnicodeString(&LinkName);
00939     ObCloseHandle(LinkHandle, KernelMode);
00940     return TRUE;
00941 }
00942 
00943 BOOLEAN
00944 NTAPI
00945 IopVerifyDiskSignature(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout,
00946                        IN PARC_DISK_SIGNATURE ArcDiskSignature,
00947                        OUT PULONG Signature)
00948 {
00949     /* First condition: having a valid partition table */
00950     if (!ArcDiskSignature->ValidPartitionTable)
00951     {
00952         return FALSE;
00953     }
00954 
00955     /* If that partition table is the MBR */
00956     if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)
00957     {
00958         /* Then check MBR signature */
00959         if (DriveLayout->Mbr.Signature == ArcDiskSignature->Signature)
00960         {
00961             /* And return it */
00962             if (Signature)
00963             {
00964                 *Signature = DriveLayout->Mbr.Signature;
00965             }
00966 
00967             return TRUE;
00968         }
00969     }
00970     /* If that partition table is the GPT */
00971     else if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT)
00972     {
00973         /* Check we are using GPT and compare GUID */
00974         if (ArcDiskSignature->IsGpt &&
00975             (((PULONG)ArcDiskSignature->GptSignature)[0] == DriveLayout->Gpt.DiskId.Data1 &&
00976              ((PUSHORT)ArcDiskSignature->GptSignature)[2] == DriveLayout->Gpt.DiskId.Data2 &&
00977              ((PUSHORT)ArcDiskSignature->GptSignature)[3] == DriveLayout->Gpt.DiskId.Data3 &&
00978              ((PULONGLONG)ArcDiskSignature->GptSignature)[1] == ((PULONGLONG)DriveLayout->Gpt.DiskId.Data4)[0]))
00979         {
00980             /* There's no signature to give, so we just zero output */
00981             if (Signature)
00982             {
00983                 *Signature = 0;
00984             }
00985             return TRUE;
00986         }
00987     }
00988 
00989     /* If we fall here, it means that something went wrong, so return that */
00990     return FALSE;
00991 }
00992 
00993 /* EOF */

Generated on Fri May 25 2012 04:17:23 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.