2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/arcname.c
5 * PURPOSE: ARC Path Initialization Functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl (ekohl@rz-online.de)
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 UNICODE_STRING IoArcHalDeviceName
, IoArcBootDeviceName
;
19 PCHAR IoLoaderArcBootDeviceName
;
20 extern PROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock
;
22 /* FUNCTIONS *****************************************************************/
27 IopApplyRosCdromArcHack(IN ULONG i
)
29 ULONG DeviceNumber
= -1;
30 OBJECT_ATTRIBUTES ObjectAttributes
;
31 ANSI_STRING InstallName
;
32 UNICODE_STRING DeviceName
;
33 CHAR Buffer
[128], RosSysPath
[16];
34 FILE_BASIC_INFORMATION FileInfo
;
37 PCONFIGURATION_INFORMATION ConfigInfo
= IoGetConfigurationInformation();
38 extern BOOLEAN InitIsWinPEMode
, ExpInTextModeSetup
;
40 /* Change this if you want ROS to boot properly from another directory */
41 sprintf(RosSysPath
, "%s", "reactos");
43 /* Only ARC Name left - Build full ARC Name */
44 p
= strstr(KeLoaderBlock
->ArcBootDeviceName
, "cdrom");
47 /* Build installer name */
48 sprintf(Buffer
, "\\Device\\CdRom%lu\\%s\\ntoskrnl.exe", i
, RosSysPath
);
49 RtlInitAnsiString(&InstallName
, Buffer
);
50 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &InstallName
, TRUE
);
51 if (!NT_SUCCESS(Status
)) return FALSE
;
53 /* Try to find the installer */
54 InitializeObjectAttributes(&ObjectAttributes
,
59 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
62 RtlFreeUnicodeString(&DeviceName
);
64 /* Check if we found the file */
65 if (NT_SUCCESS(Status
))
67 /* We did, save the device number */
72 /* Build live CD kernel name */
74 "\\Device\\CdRom%lu\\%s\\system32\\ntoskrnl.exe",
76 RtlInitAnsiString(&InstallName
, Buffer
);
77 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
80 if (!NT_SUCCESS(Status
)) return FALSE
;
83 InitializeObjectAttributes(&ObjectAttributes
,
88 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
89 if (NT_SUCCESS(Status
)) DeviceNumber
= i
;
92 RtlFreeUnicodeString(&DeviceName
);
98 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
100 /* Adjust original command line */
106 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
112 /* OK, how many disks are there? */
113 DeviceNumber
+= ConfigInfo
->DiskCount
;
115 /* Return whether this is the CD or not */
116 if ((InitIsWinPEMode
) || (ExpInTextModeSetup
))
128 IopGetDiskInformation(IN ULONG i
,
130 OUT PULONG Signature
,
131 OUT PULONG PartitionCount
,
132 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
135 ANSI_STRING TempString
;
137 UNICODE_STRING DeviceName
;
139 PDEVICE_OBJECT DeviceObject
;
140 PFILE_OBJECT FileObject
;
141 DISK_GEOMETRY DiskGeometry
;
142 PDRIVE_LAYOUT_INFORMATION DriveLayout
;
145 IO_STATUS_BLOCK StatusBlock
;
146 LARGE_INTEGER PartitionOffset
;
147 PULONG PartitionBuffer
;
150 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
152 /* Convert it to Unicode */
153 RtlInitAnsiString(&TempString
, Buffer
);
154 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
155 if (!NT_SUCCESS(Status
)) return FALSE
;
157 /* Get the device pointer */
158 Status
= IoGetDeviceObjectPointer(&DeviceName
,
159 FILE_READ_ATTRIBUTES
,
162 *DiskDeviceObject
= DeviceObject
;
164 /* Free the string */
165 RtlFreeUnicodeString(&DeviceName
);
167 /* Move on if we failed */
168 if (!NT_SUCCESS(Status
)) return FALSE
;
170 /* Build an IRP to determine the sector size */
171 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
172 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
177 sizeof(DISK_GEOMETRY
),
184 ObDereferenceObject(FileObject
);
188 /* Call the driver and check if we have to wait on it */
189 Status
= IoCallDriver(DeviceObject
, Irp
);
190 if (Status
== STATUS_PENDING
)
192 /* Wait on the driver */
193 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
194 Status
= StatusBlock
.Status
;
197 /* Check if we failed */
198 if (!NT_SUCCESS(Status
))
201 ObDereferenceObject(FileObject
);
205 /* Read the partition table */
206 Status
= IoReadPartitionTable(DeviceObject
,
207 DiskGeometry
.BytesPerSector
,
211 /* Dereference the file object */
212 ObDereferenceObject(FileObject
);
213 if (!NT_SUCCESS(Status
)) return FALSE
;
215 /* Set the offset to 0 */
216 PartitionOffset
.QuadPart
= 0;
218 /* Allocate a buffer for the partition */
219 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
220 DiskGeometry
.BytesPerSector
,
222 if (!PartitionBuffer
)
225 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
229 /* Build an IRP to read the partition sector */
230 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
231 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
234 DiskGeometry
.BytesPerSector
,
241 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
242 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
246 /* Call the driver and check if we have to wait */
247 Status
= IoCallDriver(DeviceObject
, Irp
);
248 if (Status
== STATUS_PENDING
)
250 /* Wait for completion */
251 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
252 Status
= StatusBlock
.Status
;
255 /* Check if we failed */
256 if (!NT_SUCCESS(Status
))
259 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
260 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
264 /* Calculate the MBR checksum */
266 for (j
= 0; j
< 128; j
++) Checksum
+= PartitionBuffer
[j
];
268 /* Save the signature and checksum */
269 *CheckSum
= ~Checksum
+ 1;
270 *Signature
= DriveLayout
->Signature
;
271 *PartitionCount
= DriveLayout
->PartitionCount
;
273 /* Free the buffer */
274 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
275 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
282 IopAssignArcNamesToCdrom(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
287 ANSI_STRING TempString
;
288 UNICODE_STRING DeviceName
, ArcName
;
290 LARGE_INTEGER PartitionOffset
;
292 IO_STATUS_BLOCK IoStatusBlock
;
294 ULONG i
, CheckSum
= 0;
295 PDEVICE_OBJECT DeviceObject
;
296 PFILE_OBJECT FileObject
;
297 PARC_DISK_INFORMATION ArcDiskInfo
= LoaderBlock
->ArcDiskInformation
;
298 PLIST_ENTRY NextEntry
;
299 PARC_DISK_SIGNATURE ArcDiskEntry
;
300 BOOLEAN IsBootCdRom
= FALSE
;
302 /* Build the device name */
303 sprintf(ArcBuffer
, "\\Device\\CdRom%lu", DiskNumber
);
305 /* Convert it to Unicode */
306 RtlInitAnsiString(&TempString
, ArcBuffer
);
307 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
308 if (!NT_SUCCESS(Status
)) return FALSE
;
310 /* Get the device for it */
311 Status
= IoGetDeviceObjectPointer(&DeviceName
,
312 FILE_READ_ATTRIBUTES
,
315 if (!NT_SUCCESS(Status
))
317 /* Free the string and fail */
318 RtlFreeUnicodeString(&DeviceName
);
322 /* Setup the event */
323 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
325 /* Set the offset and build the read IRP */
326 PartitionOffset
.QuadPart
= 0x8000;
327 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
336 /* Free the string and fail */
337 RtlFreeUnicodeString(&DeviceName
);
341 /* Call the driver and check if we have to wait on it */
342 Status
= IoCallDriver(DeviceObject
, Irp
);
343 if (Status
== STATUS_PENDING
)
345 /* Wait for completion */
346 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
347 Status
= IoStatusBlock
.Status
;
350 /* Dereference the file object */
351 ObDereferenceObject(FileObject
);
352 if (!NT_SUCCESS(Status
)) return FALSE
;
354 /* Now calculate the checksum */
355 for (i
= 0; i
< 2048 / sizeof(ULONG
); i
++) CheckSum
+= Buffer
[i
];
357 if (KeRosLoaderBlock
) goto freeldrhack
;
359 /* Search if this device is the actual boot CD */
360 for (NextEntry
= ArcDiskInfo
->DiskSignatureListHead
.Flink
;
361 NextEntry
!= &ArcDiskInfo
->DiskSignatureListHead
;
362 NextEntry
= NextEntry
->Flink
)
364 /* Get the current ARC disk signature entry */
365 ArcDiskEntry
= CONTAINING_RECORD(NextEntry
,
368 /* And check if checksums and arc names match */
369 if (CheckSum
== ArcDiskEntry
->CheckSum
&&
370 strcmp(KeLoaderBlock
->ArcBootDeviceName
, ArcDiskEntry
->ArcName
) == 0)
380 * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
381 * ARC Path name, and what happens here is a comparision of both checksums
382 * in order to see if this is the actual boot CD.
384 * In ReactOS this doesn't currently happen, instead we have a hack on top
385 * of this file which scans the CD for the ntoskrnl.exe file, then modifies
386 * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
387 * get the same state as if NTLDR had properly booted us, except that we do
388 * not actually need to check the signature, since the hack already did the
389 * check for ntoskrnl.exe, which is just as good.
391 * The signature code stays however, because eventually FreeLDR will work
392 * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
394 IsBootCdRom
= IopApplyRosCdromArcHack(DiskNumber
);
399 /* This is the boot CD-ROM, build the ARC name */
400 sprintf(ArcBuffer
, "\\ArcName\\%s", KeLoaderBlock
->ArcBootDeviceName
);
402 /* Convert it to Unicode */
403 RtlInitAnsiString(&TempString
, ArcBuffer
);
404 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TempString
, TRUE
);
405 if (!NT_SUCCESS(Status
)) return FALSE
;
407 /* Create the symbolic link and free the strings */
408 IoAssignArcName(&ArcName
, &DeviceName
);
409 RtlFreeUnicodeString(&ArcName
);
410 RtlFreeUnicodeString(&DeviceName
);
412 /* Let caller know that we've found the boot CD */
416 /* No boot CD found */
423 IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
425 PCONFIGURATION_INFORMATION ConfigInfo
= IoGetConfigurationInformation();
426 PARC_DISK_INFORMATION ArcDiskInfo
= LoaderBlock
->ArcDiskInformation
;
428 ANSI_STRING ArcBootString
, ArcSystemString
, ArcString
;
429 UNICODE_STRING ArcName
, BootPath
, DeviceName
;
432 PDEVICE_OBJECT DeviceObject
;
433 ULONG Signature
, Checksum
, PartitionCount
;
434 PLIST_ENTRY NextEntry
;
435 PARC_DISK_SIGNATURE ArcDiskEntry
;
437 BOOLEAN FoundBoot
= FALSE
;
438 PULONG PartitionBuffer
;
440 /* Check if we only have one disk on the machine */
441 SingleDisk
= ArcDiskInfo
->DiskSignatureListHead
.Flink
->Flink
==
442 (&ArcDiskInfo
->DiskSignatureListHead
);
444 /* Create the global HAL partition name */
445 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcHalDeviceName
);
446 RtlInitAnsiString(&ArcString
, Buffer
);
447 RtlAnsiStringToUnicodeString(&IoArcHalDeviceName
, &ArcString
, TRUE
);
449 /* Create the global system partition name */
450 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
451 RtlInitAnsiString(&ArcString
, Buffer
);
452 RtlAnsiStringToUnicodeString(&IoArcBootDeviceName
, &ArcString
, TRUE
);
454 /* Allocate memory for the string */
455 Length
= strlen(LoaderBlock
->ArcBootDeviceName
) + sizeof(ANSI_NULL
);
456 IoLoaderArcBootDeviceName
= ExAllocatePoolWithTag(PagedPool
,
459 if (IoLoaderArcBootDeviceName
)
462 RtlCopyMemory(IoLoaderArcBootDeviceName
,
463 LoaderBlock
->ArcBootDeviceName
,
467 /* Check if we only found a disk, but we're booting from CD-ROM */
468 if ((SingleDisk
) && strstr(LoaderBlock
->ArcBootDeviceName
, "cdrom"))
470 /* Then disable single-disk mode, since there's a CD drive out there */
474 /* Build the boot strings */
475 RtlInitAnsiString(&ArcBootString
, LoaderBlock
->ArcBootDeviceName
);
476 RtlInitAnsiString(&ArcSystemString
, LoaderBlock
->ArcHalDeviceName
);
478 /* Loop every detected disk */
479 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
481 /* Get information about the disk */
482 if (!IopGetDiskInformation(i
,
493 for (NextEntry
= ArcDiskInfo
->DiskSignatureListHead
.Flink
;
494 NextEntry
!= &ArcDiskInfo
->DiskSignatureListHead
;
495 NextEntry
= NextEntry
->Flink
)
497 /* Get the current ARC disk signature entry */
498 ArcDiskEntry
= CONTAINING_RECORD(NextEntry
,
503 * Now check if the signature and checksum match, unless this is
504 * the only disk that was in the ARC list, and also in the device
505 * tree, in which case the check is bypassed and we accept the disk
507 if (((SingleDisk
) && (ConfigInfo
->DiskCount
== 1)) ||
508 ((Checksum
== ArcDiskEntry
->CheckSum
) &&
509 (Signature
== ArcDiskEntry
->Signature
)))
511 /* Build the NT Device Name */
512 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
514 /* Convert it to Unicode */
515 RtlInitAnsiString(&ArcString
, Buffer
);
516 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
519 if (!NT_SUCCESS(Status
)) continue;
521 /* Build the ARC Device Name */
522 sprintf(Buffer
, "\\ArcName\\%s", ArcDiskEntry
->ArcName
);
524 /* Convert it to Unicode */
525 RtlInitAnsiString(&ArcString
, Buffer
);
526 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
529 if (!NT_SUCCESS(Status
)) continue;
531 /* Create the symbolic link and free the strings */
532 IoAssignArcName(&ArcName
, &DeviceName
);
533 RtlFreeUnicodeString(&ArcName
);
534 RtlFreeUnicodeString(&DeviceName
);
536 /* Loop all the partitions */
537 for (j
= 0; j
< PartitionCount
; j
++)
539 /* Build the partition device name */
541 "\\Device\\Harddisk%lu\\Partition%lu",
545 /* Convert it to Unicode */
546 RtlInitAnsiString(&ArcString
, Buffer
);
547 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
550 if (!NT_SUCCESS(Status
)) continue;
552 /* Build the partial ARC name for this partition */
555 ArcDiskEntry
->ArcName
,
557 RtlInitAnsiString(&ArcString
, Buffer
);
559 /* Check if this is the boot device */
560 if (RtlEqualString(&ArcString
, &ArcBootString
, TRUE
))
562 /* Remember that we found a Hard Disk Boot Device */
566 /* Check if it's the system boot partition */
567 if (RtlEqualString(&ArcString
, &ArcSystemString
, TRUE
))
569 /* It is, create a Unicode string for it */
570 RtlInitAnsiString(&ArcString
,
571 LoaderBlock
->NtHalPathName
);
572 Status
= RtlAnsiStringToUnicodeString(&BootPath
,
575 if (NT_SUCCESS(Status
))
577 /* FIXME: Save in registry */
579 /* Free the string now */
580 RtlFreeUnicodeString(&BootPath
);
584 /* Build the full ARC name */
586 "\\ArcName\\%spartition(%lu)",
587 ArcDiskEntry
->ArcName
,
590 /* Convert it to Unicode */
591 RtlInitAnsiString(&ArcString
, Buffer
);
592 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
595 if (!NT_SUCCESS(Status
)) continue;
597 /* Create the symbolic link and free the strings */
598 IoAssignArcName(&ArcName
, &DeviceName
);
599 RtlFreeUnicodeString(&ArcName
);
600 RtlFreeUnicodeString(&DeviceName
);
606 /* Check if we didn't find the boot disk */
609 /* Allocate a buffer for the CD-ROM MBR */
610 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
, 2048, TAG_IO
);
611 if (!PartitionBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
613 /* Loop every CD-ROM */
614 for (i
= 0; i
< ConfigInfo
->CdRomCount
; i
++)
616 /* Give it an ARC name */
617 if (IopAssignArcNamesToCdrom(LoaderBlock
, PartitionBuffer
, i
)) break;
620 /* Free the buffer */
621 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
625 return STATUS_SUCCESS
;
630 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
631 OUT PANSI_STRING NtBootPath
)
633 OBJECT_ATTRIBUTES ObjectAttributes
;
635 CHAR Buffer
[256], AnsiBuffer
[256];
636 WCHAR ArcNameBuffer
[64];
637 ANSI_STRING TargetString
, ArcString
, TempString
;
638 UNICODE_STRING LinkName
, TargetName
, ArcName
;
641 /* Create the Unicode name for the current ARC boot device */
642 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
643 RtlInitAnsiString(&TargetString
, Buffer
);
644 Status
= RtlAnsiStringToUnicodeString(&TargetName
, &TargetString
, TRUE
);
645 if (!NT_SUCCESS(Status
)) return FALSE
;
647 /* Initialize the attributes and open the link */
648 InitializeObjectAttributes(&ObjectAttributes
,
650 OBJ_CASE_INSENSITIVE
,
653 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
654 SYMBOLIC_LINK_ALL_ACCESS
,
656 if (!NT_SUCCESS(Status
))
658 /* We failed, free the string */
659 RtlFreeUnicodeString(&TargetName
);
663 /* Query the current \\SystemRoot */
664 ArcName
.Buffer
= ArcNameBuffer
;
666 ArcName
.MaximumLength
= sizeof(ArcNameBuffer
);
667 Status
= NtQuerySymbolicLinkObject(LinkHandle
, &ArcName
, NULL
);
668 if (!NT_SUCCESS(Status
))
670 /* We failed, free the string */
671 RtlFreeUnicodeString(&TargetName
);
675 /* Convert it to Ansi */
676 ArcString
.Buffer
= AnsiBuffer
;
677 ArcString
.Length
= 0;
678 ArcString
.MaximumLength
= sizeof(AnsiBuffer
);
679 Status
= RtlUnicodeStringToAnsiString(&ArcString
, &ArcName
, FALSE
);
680 AnsiBuffer
[ArcString
.Length
] = ANSI_NULL
;
682 /* Close the link handle and free the name */
683 ObCloseHandle(LinkHandle
, KernelMode
);
684 RtlFreeUnicodeString(&TargetName
);
686 /* Setup the system root name again */
687 RtlInitAnsiString(&TempString
, "\\SystemRoot");
688 Status
= RtlAnsiStringToUnicodeString(&LinkName
, &TempString
, TRUE
);
689 if (!NT_SUCCESS(Status
)) return FALSE
;
691 /* Open the symbolic link for it */
692 InitializeObjectAttributes(&ObjectAttributes
,
694 OBJ_CASE_INSENSITIVE
,
697 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
698 SYMBOLIC_LINK_ALL_ACCESS
,
700 if (!NT_SUCCESS(Status
)) return FALSE
;
703 NtMakeTemporaryObject(LinkHandle
);
704 ObCloseHandle(LinkHandle
, KernelMode
);
706 /* Now create the new name for it */
707 sprintf(Buffer
, "%s%s", ArcString
.Buffer
, LoaderBlock
->NtBootPathName
);
709 /* Copy it into the passed parameter and null-terminate it */
710 RtlCopyString(NtBootPath
, &ArcString
);
711 Buffer
[strlen(Buffer
) - 1] = ANSI_NULL
;
713 /* Setup the Unicode-name for the new symbolic link value */
714 RtlInitAnsiString(&TargetString
, Buffer
);
715 InitializeObjectAttributes(&ObjectAttributes
,
717 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
720 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TargetString
, TRUE
);
721 if (!NT_SUCCESS(Status
)) return FALSE
;
724 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
725 SYMBOLIC_LINK_ALL_ACCESS
,
729 /* Free all the strings and close the handle and return success */
730 RtlFreeUnicodeString(&ArcName
);
731 RtlFreeUnicodeString(&LinkName
);
732 ObCloseHandle(LinkHandle
, KernelMode
);