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
;
21 /* FUNCTIONS *****************************************************************/
26 IopApplyRosCdromArcHack(IN ULONG i
)
28 ULONG DeviceNumber
= -1;
29 OBJECT_ATTRIBUTES ObjectAttributes
;
30 ANSI_STRING InstallName
;
31 UNICODE_STRING DeviceName
;
33 FILE_BASIC_INFORMATION FileInfo
;
37 /* Only ARC Name left - Build full ARC Name */
38 p
= strstr(KeLoaderBlock
->ArcBootDeviceName
, "cdrom");
41 /* Build installer name */
42 sprintf(Buffer
, "\\Device\\CdRom%lu\\reactos\\ntoskrnl.exe", i
);
43 RtlInitAnsiString(&InstallName
, Buffer
);
44 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &InstallName
, TRUE
);
45 if (!NT_SUCCESS(Status
)) return FALSE
;
47 /* Try to find the installer */
48 InitializeObjectAttributes(&ObjectAttributes
,
53 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
56 RtlFreeUnicodeString(&DeviceName
);
58 /* Check if we found the file */
59 if (NT_SUCCESS(Status
))
61 /* We did, save the device number */
66 /* Build live CD kernel name */
68 "\\Device\\CdRom%lu\\reactos\\system32\\ntoskrnl.exe",
70 RtlInitAnsiString(&InstallName
, Buffer
);
71 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
74 if (!NT_SUCCESS(Status
)) return FALSE
;
77 InitializeObjectAttributes(&ObjectAttributes
,
82 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
83 if (NT_SUCCESS(Status
)) DeviceNumber
= i
;
86 RtlFreeUnicodeString(&DeviceName
);
90 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
92 /* Adjust original command line */
98 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
103 /* Return whether this is the CD or not */
104 if (DeviceNumber
!= 1)
106 /* Hack until IoAssignDriveLetters is fixed */
107 swprintf(SharedUserData
->NtSystemRoot
, L
"D:\\reactos");
118 IopGetDiskInformation(IN ULONG i
,
120 OUT PULONG Signature
,
121 OUT PULONG PartitionCount
,
122 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
125 ANSI_STRING TempString
;
127 UNICODE_STRING DeviceName
;
129 PDEVICE_OBJECT DeviceObject
;
130 PFILE_OBJECT FileObject
;
131 DISK_GEOMETRY DiskGeometry
;
132 PDRIVE_LAYOUT_INFORMATION DriveLayout
;
135 IO_STATUS_BLOCK StatusBlock
;
136 LARGE_INTEGER PartitionOffset
;
137 PPARTITION_SECTOR PartitionBuffer
;
140 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
142 /* Convert it to Unicode */
143 RtlInitAnsiString(&TempString
, Buffer
);
144 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
145 if (!NT_SUCCESS(Status
)) return FALSE
;
147 /* Get the device pointer */
148 Status
= IoGetDeviceObjectPointer(&DeviceName
,
152 *DiskDeviceObject
= DeviceObject
;
154 /* Free the string */
155 RtlFreeUnicodeString(&DeviceName
);
157 /* Move on if we failed */
158 if (!NT_SUCCESS(Status
)) return FALSE
;
160 /* Build an IRP to determine the sector size */
161 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
162 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
167 sizeof(DISK_GEOMETRY
),
174 ObDereferenceObject(FileObject
);
178 /* Call the driver and check if we have to wait on it */
179 Status
= IoCallDriver(DeviceObject
, Irp
);
180 if (Status
== STATUS_PENDING
)
182 /* Wait on the driver */
183 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
184 Status
= StatusBlock
.Status
;
187 /* Check if we failed */
188 if (!NT_SUCCESS(Status
))
191 ObDereferenceObject(FileObject
);
195 /* Read the partition table */
196 Status
= IoReadPartitionTable(DeviceObject
,
197 DiskGeometry
.BytesPerSector
,
201 /* Dereference the file object */
202 ObDereferenceObject(FileObject
);
203 if (!NT_SUCCESS(Status
)) return FALSE
;
205 /* Set the offset to 0 */
206 PartitionOffset
.QuadPart
= 0;
208 /* Allocate a buffer for the partition */
209 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
210 DiskGeometry
.BytesPerSector
,
212 if (!PartitionBuffer
) return FALSE
;
214 /* Build an IRP to read the partition sector */
215 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
216 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
219 DiskGeometry
.BytesPerSector
,
224 /* Call the driver and check if we have to wait */
225 Status
= IoCallDriver(DeviceObject
, Irp
);
226 if (Status
== STATUS_PENDING
)
228 /* Wait for completion */
229 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
230 Status
= StatusBlock
.Status
;
233 /* Check if we failed */
234 if (!NT_SUCCESS(Status
))
237 ExFreePool(PartitionBuffer
);
238 ExFreePool(DriveLayout
);
242 /* Calculate the MBR checksum */
244 for (j
= 0; j
< 128; j
++)
246 Checksum
+= ((PULONG
)PartitionBuffer
)[j
];
249 /* Save the signature and checksum */
250 *CheckSum
= ~Checksum
+ 1;
251 *Signature
= DriveLayout
->Signature
;
252 *PartitionCount
= DriveLayout
->PartitionCount
;
254 /* Free the buffer */
255 ExFreePool(PartitionBuffer
);
256 ExFreePool(DriveLayout
);
263 IopAssignArcNamesToCdrom(IN PULONG Buffer
,
267 ANSI_STRING TempString
;
268 UNICODE_STRING DeviceName
, ArcName
;
270 LARGE_INTEGER PartitionOffset
;
272 IO_STATUS_BLOCK IoStatusBlock
;
274 ULONG i
, CheckSum
= 0;
275 PDEVICE_OBJECT DeviceObject
;
276 PFILE_OBJECT FileObject
;
278 /* Build the device name */
279 sprintf(ArcBuffer
, "\\Device\\CdRom%lu", DiskNumber
);
281 /* Convert it to Unicode */
282 RtlInitAnsiString(&TempString
, ArcBuffer
);
283 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
284 if (!NT_SUCCESS(Status
)) return FALSE
;
286 /* Get the device for it */
287 Status
= IoGetDeviceObjectPointer(&DeviceName
,
288 FILE_READ_ATTRIBUTES
,
291 if (!NT_SUCCESS(Status
))
293 /* Free the string and fail */
294 RtlFreeUnicodeString(&DeviceName
);
298 /* Setup the event */
299 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
301 /* Set the offset and build the read IRP */
302 PartitionOffset
.QuadPart
= 0x8000;
303 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
312 /* Free the string and fail */
313 RtlFreeUnicodeString(&DeviceName
);
317 /* Call the driver and check if we have to wait on it */
318 Status
= IoCallDriver(DeviceObject
, Irp
);
319 if (Status
== STATUS_PENDING
)
321 /* Wait for completion */
322 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
323 Status
= IoStatusBlock
.Status
;
326 /* Dereference the file object */
327 ObDereferenceObject(FileObject
);
328 if (!NT_SUCCESS(Status
)) return FALSE
;
330 /* Now calculate the checksum */
331 for (i
= 0; i
< 2048 / sizeof(ULONG
); i
++) CheckSum
+= Buffer
[i
];
334 * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
335 * ARC Path name, and what happens here is a comparision of both checksums
336 * in order to see if this is the actual boot CD.
338 * In ReactOS this doesn't currently happen, instead we have a hack on top
339 * of this file which scans the CD for the ntoskrnl.exe file, then modifies
340 * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
341 * get the same state as if NTLDR had properly booted us, except that we do
342 * not actually need to check the signature, since the hack already did the
343 * check for ntoskrnl.exe, which is just as good.
345 * The signature code stays however, because eventually FreeLDR will work
346 * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
348 if (IopApplyRosCdromArcHack(DiskNumber
))
350 /* This is the boot CD-ROM, build the ARC name */
351 sprintf(ArcBuffer
, "\\ArcName\\%s", KeLoaderBlock
->ArcBootDeviceName
);
353 /* Convert it to Unicode */
354 RtlInitAnsiString(&TempString
, ArcBuffer
);
355 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TempString
, TRUE
);
356 if (!NT_SUCCESS(Status
)) return FALSE
;
358 /* Create the symbolic link and free the strings */
359 IoAssignArcName(&ArcName
, &DeviceName
);
360 RtlFreeUnicodeString(&ArcName
);
361 RtlFreeUnicodeString(&DeviceName
);
363 /* Let caller know that we've found the boot CD */
367 /* No boot CD found */
374 IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
376 PCONFIGURATION_INFORMATION ConfigInfo
= IoGetConfigurationInformation();
377 PARC_DISK_INFORMATION ArcDiskInfo
= LoaderBlock
->ArcDiskInformation
;
379 ANSI_STRING ArcBootString
, ArcSystemString
, ArcString
;
380 UNICODE_STRING ArcName
, BootPath
, DeviceName
;
383 PDEVICE_OBJECT DeviceObject
;
384 ULONG Signature
, Checksum
, PartitionCount
;
385 PLIST_ENTRY NextEntry
;
386 PARC_DISK_SIGNATURE ArcDiskEntry
;
388 BOOLEAN FoundBoot
= FALSE
;
389 PULONG PartitionBuffer
;
391 /* Check if we only have one disk on the machine */
392 SingleDisk
= ArcDiskInfo
->DiskSignatureListHead
.Flink
->Flink
==
393 (&ArcDiskInfo
->DiskSignatureListHead
);
395 /* Create the global HAL partition name */
396 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcHalDeviceName
);
397 RtlInitAnsiString(&ArcString
, Buffer
);
398 RtlAnsiStringToUnicodeString(&IoArcHalDeviceName
, &ArcString
, TRUE
);
400 /* Create the global system partition name */
401 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
402 RtlInitAnsiString(&ArcString
, Buffer
);
403 RtlAnsiStringToUnicodeString(&IoArcBootDeviceName
, &ArcString
, TRUE
);
405 /* Allocate memory for the string */
406 Length
= strlen(LoaderBlock
->ArcBootDeviceName
) + sizeof(ANSI_NULL
);
407 IoLoaderArcBootDeviceName
= ExAllocatePoolWithTag(PagedPool
,
410 if (IoLoaderArcBootDeviceName
)
413 RtlCopyMemory(IoLoaderArcBootDeviceName
,
414 LoaderBlock
->ArcBootDeviceName
,
418 /* Check if we only found a disk, but we're booting from CD-ROM */
419 if ((SingleDisk
) && strstr(LoaderBlock
->ArcBootDeviceName
, "cdrom"))
421 /* Then disable single-disk mode, since there's a CD drive out there */
425 /* Build the boot strings */
426 RtlInitAnsiString(&ArcBootString
, LoaderBlock
->ArcBootDeviceName
);
427 RtlInitAnsiString(&ArcSystemString
, LoaderBlock
->ArcHalDeviceName
);
429 /* Loop every detected disk */
430 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
432 /* Get information about the disk */
433 if (!IopGetDiskInformation(i
,
444 for (NextEntry
= ArcDiskInfo
->DiskSignatureListHead
.Flink
;
445 NextEntry
!= &ArcDiskInfo
->DiskSignatureListHead
;
446 NextEntry
= NextEntry
->Flink
)
448 /* Get the current ARC disk signature entry */
449 ArcDiskEntry
= CONTAINING_RECORD(NextEntry
,
454 * Now check if the signature and checksum match, unless this is
455 * the only disk that was in the ARC list, and also in the device
456 * tree, in which case the check is bypassed and we accept the disk
458 if (((SingleDisk
) && (ConfigInfo
->DiskCount
== 1)) ||
459 ((Checksum
== ArcDiskEntry
->CheckSum
) &&
460 (Signature
== ArcDiskEntry
->Signature
)))
462 /* Build the NT Device Name */
463 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
465 /* Convert it to Unicode */
466 RtlInitAnsiString(&ArcString
, Buffer
);
467 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
470 if (!NT_SUCCESS(Status
)) continue;
472 /* Build the ARC Device Name */
473 sprintf(Buffer
, "\\ArcName\\%s", ArcDiskEntry
->ArcName
);
475 /* Convert it to Unicode */
476 RtlInitAnsiString(&ArcString
, Buffer
);
477 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
480 if (!NT_SUCCESS(Status
)) continue;
482 /* Create the symbolic link and free the strings */
483 IoAssignArcName(&ArcName
, &DeviceName
);
484 RtlFreeUnicodeString(&ArcName
);
485 RtlFreeUnicodeString(&DeviceName
);
487 /* Loop all the partitions */
488 for (j
= 0; j
< PartitionCount
; j
++)
490 /* Build the partition device name */
492 "\\Device\\Harddisk%lu\\Partition%lu",
496 /* Convert it to Unicode */
497 RtlInitAnsiString(&ArcString
, Buffer
);
498 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
501 if (!NT_SUCCESS(Status
)) continue;
503 /* Build the partial ARC name for this partition */
506 ArcDiskEntry
->ArcName
,
508 RtlInitAnsiString(&ArcString
, Buffer
);
510 /* Check if this is the boot device */
511 if (RtlEqualString(&ArcString
, &ArcBootString
, TRUE
))
513 /* Remember that we found a Hard Disk Boot Device */
517 /* Check if it's the system boot partition */
518 if (RtlEqualString(&ArcString
, &ArcSystemString
, TRUE
))
520 /* It is, create a Unicode string for it */
521 RtlInitAnsiString(&ArcString
,
522 LoaderBlock
->NtHalPathName
);
523 Status
= RtlAnsiStringToUnicodeString(&BootPath
,
526 if (NT_SUCCESS(Status
))
528 /* FIXME: Save in registry */
530 /* Free the string now */
531 RtlFreeUnicodeString(&BootPath
);
535 /* Build the full ARC name */
537 "\\ArcName\\%spartition(%lu)",
538 ArcDiskEntry
->ArcName
,
541 /* Convert it to Unicode */
542 RtlInitAnsiString(&ArcString
, Buffer
);
543 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
546 if (!NT_SUCCESS(Status
)) continue;
548 /* Create the symbolic link and free the strings */
549 IoAssignArcName(&ArcName
, &DeviceName
);
550 RtlFreeUnicodeString(&ArcName
);
551 RtlFreeUnicodeString(&DeviceName
);
557 /* Check if we didn't find the boot disk */
560 /* Allocate a buffer for the CD-ROM MBR */
561 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
, 2048, TAG_IO
);
562 if (!PartitionBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
564 /* Loop every CD-ROM */
565 for (i
= 0; i
< ConfigInfo
->CdRomCount
; i
++)
567 /* Give it an ARC name */
568 if (IopAssignArcNamesToCdrom(PartitionBuffer
, i
)) break;
571 /* Free the buffer */
572 ExFreePool(PartitionBuffer
);
576 return STATUS_SUCCESS
;
581 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
582 OUT PANSI_STRING NtBootPath
)
584 OBJECT_ATTRIBUTES ObjectAttributes
;
586 CHAR Buffer
[256], AnsiBuffer
[256];
587 WCHAR ArcNameBuffer
[64];
588 ANSI_STRING TargetString
, ArcString
, TempString
;
589 UNICODE_STRING LinkName
, TargetName
, ArcName
;
592 /* Create the Unicode name for the current ARC boot device */
593 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
594 RtlInitAnsiString(&TargetString
, Buffer
);
595 Status
= RtlAnsiStringToUnicodeString(&TargetName
, &TargetString
, TRUE
);
596 if (!NT_SUCCESS(Status
)) return FALSE
;
598 /* Initialize the attributes and open the link */
599 InitializeObjectAttributes(&ObjectAttributes
,
601 OBJ_CASE_INSENSITIVE
,
604 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
605 SYMBOLIC_LINK_ALL_ACCESS
,
607 if (!NT_SUCCESS(Status
))
609 /* We failed, free the string */
610 RtlFreeUnicodeString(&TargetName
);
614 /* Query the current \\SystemRoot */
615 ArcName
.Buffer
= ArcNameBuffer
;
617 ArcName
.MaximumLength
= sizeof(ArcNameBuffer
);
618 Status
= NtQuerySymbolicLinkObject(LinkHandle
, &ArcName
, NULL
);
619 if (!NT_SUCCESS(Status
))
621 /* We failed, free the string */
622 RtlFreeUnicodeString(&TargetName
);
626 /* Convert it to Ansi */
627 ArcString
.Buffer
= AnsiBuffer
;
628 ArcString
.Length
= 0;
629 ArcString
.MaximumLength
= sizeof(AnsiBuffer
);
630 Status
= RtlUnicodeStringToAnsiString(&ArcString
, &ArcName
, FALSE
);
631 AnsiBuffer
[ArcString
.Length
] = ANSI_NULL
;
633 /* Close the link handle and free the name */
634 ObCloseHandle(LinkHandle
, KernelMode
);
635 RtlFreeUnicodeString(&TargetName
);
637 /* Setup the system root name again */
638 RtlInitAnsiString(&TempString
, "\\SystemRoot");
639 Status
= RtlAnsiStringToUnicodeString(&LinkName
, &TempString
, TRUE
);
640 if (!NT_SUCCESS(Status
)) return FALSE
;
642 /* Open the symbolic link for it */
643 InitializeObjectAttributes(&ObjectAttributes
,
645 OBJ_CASE_INSENSITIVE
,
648 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
649 SYMBOLIC_LINK_ALL_ACCESS
,
651 if (!NT_SUCCESS(Status
)) return FALSE
;
654 NtMakeTemporaryObject(LinkHandle
);
655 ObCloseHandle(LinkHandle
, KernelMode
);
657 /* Now create the new name for it */
658 sprintf(Buffer
, "%s%s", ArcString
.Buffer
, LoaderBlock
->NtBootPathName
);
660 /* Copy it into the passed parameter and null-terminate it */
661 RtlCopyString(NtBootPath
, &ArcString
);
662 Buffer
[strlen(Buffer
) - 1] = ANSI_NULL
;
664 /* Setup the Unicode-name for the new symbolic link value */
665 RtlInitAnsiString(&TargetString
, Buffer
);
666 InitializeObjectAttributes(&ObjectAttributes
,
668 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
671 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TargetString
, TRUE
);
672 if (!NT_SUCCESS(Status
)) return FALSE
;
675 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
676 SYMBOLIC_LINK_ALL_ACCESS
,
680 /* Free all the strings and close the handle and return success */
681 RtlFreeUnicodeString(&ArcName
);
682 RtlFreeUnicodeString(&LinkName
);
683 ObCloseHandle(LinkHandle
, KernelMode
);