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) return TRUE
;
111 IopGetDiskInformation(IN ULONG i
,
113 OUT PULONG Signature
,
114 OUT PULONG PartitionCount
,
115 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
118 ANSI_STRING TempString
;
120 UNICODE_STRING DeviceName
;
122 PDEVICE_OBJECT DeviceObject
;
123 PFILE_OBJECT FileObject
;
124 DISK_GEOMETRY DiskGeometry
;
125 PDRIVE_LAYOUT_INFORMATION DriveLayout
;
128 IO_STATUS_BLOCK StatusBlock
;
129 LARGE_INTEGER PartitionOffset
;
130 PPARTITION_SECTOR PartitionBuffer
;
133 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
135 /* Convert it to Unicode */
136 RtlInitAnsiString(&TempString
, Buffer
);
137 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
138 if (!NT_SUCCESS(Status
)) return FALSE
;
140 /* Get the device pointer */
141 Status
= IoGetDeviceObjectPointer(&DeviceName
,
145 *DiskDeviceObject
= DeviceObject
;
147 /* Free the string */
148 RtlFreeUnicodeString(&DeviceName
);
150 /* Move on if we failed */
151 if (!NT_SUCCESS(Status
)) return FALSE
;
153 /* Build an IRP to determine the sector size */
154 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
155 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
160 sizeof(DISK_GEOMETRY
),
167 ObDereferenceObject(FileObject
);
171 /* Call the driver and check if we have to wait on it */
172 Status
= IoCallDriver(DeviceObject
, Irp
);
173 if (Status
== STATUS_PENDING
)
175 /* Wait on the driver */
176 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
177 Status
= StatusBlock
.Status
;
180 /* Check if we failed */
181 if (!NT_SUCCESS(Status
))
184 ObDereferenceObject(FileObject
);
188 /* Read the partition table */
189 Status
= IoReadPartitionTable(DeviceObject
,
190 DiskGeometry
.BytesPerSector
,
194 /* Dereference the file object */
195 ObDereferenceObject(FileObject
);
196 if (!NT_SUCCESS(Status
)) return FALSE
;
198 /* Set the offset to 0 */
199 PartitionOffset
.QuadPart
= 0;
201 /* Allocate a buffer for the partition */
202 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
203 DiskGeometry
.BytesPerSector
,
205 if (!PartitionBuffer
) return FALSE
;
207 /* Build an IRP to read the partition sector */
208 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
209 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
212 DiskGeometry
.BytesPerSector
,
217 /* Call the driver and check if we have to wait */
218 Status
= IoCallDriver(DeviceObject
, Irp
);
219 if (Status
== STATUS_PENDING
)
221 /* Wait for completion */
222 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
223 Status
= StatusBlock
.Status
;
226 /* Check if we failed */
227 if (!NT_SUCCESS(Status
))
230 ExFreePool(PartitionBuffer
);
231 ExFreePool(DriveLayout
);
235 /* Calculate the MBR checksum */
237 for (j
= 0; j
< 128; j
++)
239 Checksum
+= ((PULONG
)PartitionBuffer
)[j
];
242 /* Save the signature and checksum */
243 *CheckSum
= ~Checksum
+ 1;
244 *Signature
= DriveLayout
->Signature
;
245 *PartitionCount
= DriveLayout
->PartitionCount
;
247 /* Free the buffer */
248 ExFreePool(PartitionBuffer
);
249 ExFreePool(DriveLayout
);
256 IopAssignArcNamesToCdrom(IN PULONG Buffer
,
260 ANSI_STRING TempString
;
261 UNICODE_STRING DeviceName
, ArcName
;
263 LARGE_INTEGER PartitionOffset
;
265 IO_STATUS_BLOCK IoStatusBlock
;
267 ULONG i
, CheckSum
= 0;
268 PDEVICE_OBJECT DeviceObject
;
269 PFILE_OBJECT FileObject
;
271 /* Build the device name */
272 sprintf(ArcBuffer
, "\\Device\\CdRom%lu", DiskNumber
);
274 /* Convert it to Unicode */
275 RtlInitAnsiString(&TempString
, ArcBuffer
);
276 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
277 if (!NT_SUCCESS(Status
)) return FALSE
;
279 /* Get the device for it */
280 Status
= IoGetDeviceObjectPointer(&DeviceName
,
281 FILE_READ_ATTRIBUTES
,
284 if (!NT_SUCCESS(Status
))
286 /* Free the string and fail */
287 RtlFreeUnicodeString(&DeviceName
);
291 /* Setup the event */
292 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
294 /* Set the offset and build the read IRP */
295 PartitionOffset
.QuadPart
= 0x8000;
296 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
305 /* Free the string and fail */
306 RtlFreeUnicodeString(&DeviceName
);
310 /* Call the driver and check if we have to wait on it */
311 Status
= IoCallDriver(DeviceObject
, Irp
);
312 if (Status
== STATUS_PENDING
)
314 /* Wait for completion */
315 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
316 Status
= IoStatusBlock
.Status
;
319 /* Dereference the file object */
320 ObDereferenceObject(FileObject
);
321 if (!NT_SUCCESS(Status
)) return FALSE
;
323 /* Now calculate the checksum */
324 for (i
= 0; i
< 2048 / sizeof(ULONG
); i
++) CheckSum
+= Buffer
[i
];
327 * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
328 * ARC Path name, and what happens here is a comparision of both checksums
329 * in order to see if this is the actual boot CD.
331 * In ReactOS this doesn't currently happen, instead we have a hack on top
332 * of this file which scans the CD for the ntoskrnl.exe file, then modifies
333 * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
334 * get the same state as if NTLDR had properly booted us, except that we do
335 * not actually need to check the signature, since the hack already did the
336 * check for ntoskrnl.exe, which is just as good.
338 * The signature code stays however, because eventually FreeLDR will work
339 * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
341 if (IopApplyRosCdromArcHack(DiskNumber
))
343 /* This is the boot CD-ROM, build the ARC name */
344 sprintf(ArcBuffer
, "\\ArcName\\%s", KeLoaderBlock
->ArcBootDeviceName
);
346 /* Convert it to Unicode */
347 RtlInitAnsiString(&TempString
, ArcBuffer
);
348 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TempString
, TRUE
);
349 if (!NT_SUCCESS(Status
)) return FALSE
;
351 /* Create the symbolic link and free the strings */
352 IoAssignArcName(&ArcName
, &DeviceName
);
353 RtlFreeUnicodeString(&ArcName
);
354 RtlFreeUnicodeString(&DeviceName
);
356 /* Let caller know that we've found the boot CD */
360 /* No boot CD found */
367 IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
369 PCONFIGURATION_INFORMATION ConfigInfo
= IoGetConfigurationInformation();
370 PARC_DISK_INFORMATION ArcDiskInfo
= LoaderBlock
->ArcDiskInformation
;
372 ANSI_STRING ArcBootString
, ArcSystemString
, ArcString
;
373 UNICODE_STRING ArcName
, BootPath
, DeviceName
;
376 PDEVICE_OBJECT DeviceObject
;
377 ULONG Signature
, Checksum
, PartitionCount
;
378 PLIST_ENTRY NextEntry
;
379 PARC_DISK_SIGNATURE ArcDiskEntry
;
381 BOOLEAN FoundBoot
= FALSE
;
382 PULONG PartitionBuffer
;
384 /* Check if we only have one disk on the machine */
385 SingleDisk
= ArcDiskInfo
->DiskSignatureListHead
.Flink
->Flink
==
386 (&ArcDiskInfo
->DiskSignatureListHead
);
388 /* Create the global HAL partition name */
389 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcHalDeviceName
);
390 RtlInitAnsiString(&ArcString
, Buffer
);
391 RtlAnsiStringToUnicodeString(&IoArcHalDeviceName
, &ArcString
, TRUE
);
393 /* Create the global system partition name */
394 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
395 RtlInitAnsiString(&ArcString
, Buffer
);
396 RtlAnsiStringToUnicodeString(&IoArcBootDeviceName
, &ArcString
, TRUE
);
398 /* Allocate memory for the string */
399 Length
= strlen(LoaderBlock
->ArcBootDeviceName
) + sizeof(ANSI_NULL
);
400 IoLoaderArcBootDeviceName
= ExAllocatePoolWithTag(PagedPool
,
403 if (IoLoaderArcBootDeviceName
)
406 RtlMoveMemory(IoLoaderArcBootDeviceName
,
407 LoaderBlock
->ArcBootDeviceName
,
411 /* Check if we only found a disk, but we're booting from CD-ROM */
412 if ((SingleDisk
) && strstr(LoaderBlock
->ArcBootDeviceName
, "cdrom"))
414 /* Then disable single-disk mode, since there's a CD drive out there */
418 /* Build the boot strings */
419 RtlInitAnsiString(&ArcBootString
, LoaderBlock
->ArcBootDeviceName
);
420 RtlInitAnsiString(&ArcSystemString
, LoaderBlock
->ArcHalDeviceName
);
422 /* Loop every detected disk */
423 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
425 /* Get information about the disk */
426 if (!IopGetDiskInformation(i
,
437 for (NextEntry
= ArcDiskInfo
->DiskSignatureListHead
.Flink
;
438 NextEntry
!= &ArcDiskInfo
->DiskSignatureListHead
;
439 NextEntry
= NextEntry
->Flink
)
441 /* Get the current ARC disk signature entry */
442 ArcDiskEntry
= CONTAINING_RECORD(NextEntry
,
447 * Now check if the signature and checksum match, unless this is
448 * the only disk that was in the ARC list, and also in the device
449 * tree, in which case the check is bypassed and we accept the disk
451 if (((SingleDisk
) && (ConfigInfo
->DiskCount
== 1)) ||
452 ((Checksum
== ArcDiskEntry
->CheckSum
) &&
453 (Signature
== ArcDiskEntry
->Signature
)))
455 /* Build the NT Device Name */
456 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
458 /* Convert it to Unicode */
459 RtlInitAnsiString(&ArcString
, Buffer
);
460 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
463 if (!NT_SUCCESS(Status
)) continue;
465 /* Build the ARC Device Name */
466 sprintf(Buffer
, "\\ArcName\\%s", ArcDiskEntry
->ArcName
);
468 /* Convert it to Unicode */
469 RtlInitAnsiString(&ArcString
, Buffer
);
470 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
473 if (!NT_SUCCESS(Status
)) continue;
475 /* Create the symbolic link and free the strings */
476 IoAssignArcName(&ArcName
, &DeviceName
);
477 RtlFreeUnicodeString(&ArcName
);
478 RtlFreeUnicodeString(&DeviceName
);
480 /* Loop all the partitions */
481 for (j
= 0; j
< PartitionCount
; j
++)
483 /* Build the partition device name */
485 "\\Device\\Harddisk%lu\\Partition%lu",
489 /* Convert it to Unicode */
490 RtlInitAnsiString(&ArcString
, Buffer
);
491 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
494 if (!NT_SUCCESS(Status
)) continue;
496 /* Build the partial ARC name for this partition */
499 ArcDiskEntry
->ArcName
,
501 RtlInitAnsiString(&ArcString
, Buffer
);
503 /* Check if this is the boot device */
504 if (RtlEqualString(&ArcString
, &ArcBootString
, TRUE
))
506 /* Remember that we found a Hard Disk Boot Device */
510 /* Check if it's the system boot partition */
511 if (RtlEqualString(&ArcString
, &ArcSystemString
, TRUE
))
513 /* It is, create a Unicode string for it */
514 RtlInitAnsiString(&ArcString
,
515 LoaderBlock
->NtHalPathName
);
516 Status
= RtlAnsiStringToUnicodeString(&BootPath
,
519 if (NT_SUCCESS(Status
))
521 /* FIXME: Save in registry */
523 /* Free the string now */
524 RtlFreeUnicodeString(&BootPath
);
528 /* Build the full ARC name */
530 "\\ArcName\\%spartition(%lu)",
531 ArcDiskEntry
->ArcName
,
534 /* Convert it to Unicode */
535 RtlInitAnsiString(&ArcString
, Buffer
);
536 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
539 if (!NT_SUCCESS(Status
)) continue;
541 /* Create the symbolic link and free the strings */
542 IoAssignArcName(&ArcName
, &DeviceName
);
543 RtlFreeUnicodeString(&ArcName
);
544 RtlFreeUnicodeString(&DeviceName
);
550 /* Check if we didn't find the boot disk */
553 /* Allocate a buffer for the CD-ROM MBR */
554 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
, 2048, TAG_IO
);
555 if (!PartitionBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
557 /* Loop every CD-ROM */
558 for (i
= 0; i
< ConfigInfo
->CdRomCount
; i
++)
560 /* Give it an ARC name */
561 if (IopAssignArcNamesToCdrom(PartitionBuffer
, i
)) break;
564 /* Free the buffer */
565 ExFreePool(PartitionBuffer
);
569 return STATUS_SUCCESS
;
574 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
575 OUT PANSI_STRING NtBootPath
)
577 OBJECT_ATTRIBUTES ObjectAttributes
;
579 CHAR Buffer
[256], AnsiBuffer
[256];
580 WCHAR ArcNameBuffer
[64];
581 ANSI_STRING TargetString
, ArcString
, TempString
;
582 UNICODE_STRING LinkName
, TargetName
, ArcName
;
585 /* Create the Unicode name for the current ARC boot device */
586 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
587 RtlInitAnsiString(&TargetString
, Buffer
);
588 Status
= RtlAnsiStringToUnicodeString(&TargetName
, &TargetString
, TRUE
);
589 if (!NT_SUCCESS(Status
)) return FALSE
;
591 /* Initialize the attributes and open the link */
592 InitializeObjectAttributes(&ObjectAttributes
,
594 OBJ_CASE_INSENSITIVE
,
597 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
598 SYMBOLIC_LINK_ALL_ACCESS
,
600 if (!NT_SUCCESS(Status
))
602 /* We failed, free the string */
603 RtlFreeUnicodeString(&TargetName
);
607 /* Query the current \\SystemRoot */
608 ArcName
.Buffer
= ArcNameBuffer
;
610 ArcName
.MaximumLength
= sizeof(ArcNameBuffer
);
611 Status
= NtQuerySymbolicLinkObject(LinkHandle
, &ArcName
, NULL
);
612 if (!NT_SUCCESS(Status
))
614 /* We failed, free the string */
615 RtlFreeUnicodeString(&TargetName
);
619 /* Convert it to Ansi */
620 ArcString
.Buffer
= AnsiBuffer
;
621 ArcString
.Length
= 0;
622 ArcString
.MaximumLength
= sizeof(AnsiBuffer
);
623 Status
= RtlUnicodeStringToAnsiString(&ArcString
, &ArcName
, FALSE
);
624 AnsiBuffer
[ArcString
.Length
] = ANSI_NULL
;
626 /* Close the link handle and free the name */
627 ObCloseHandle(LinkHandle
, KernelMode
);
628 RtlFreeUnicodeString(&TargetName
);
630 /* Setup the system root name again */
631 RtlInitAnsiString(&TempString
, "\\SystemRoot");
632 Status
= RtlAnsiStringToUnicodeString(&LinkName
, &TempString
, TRUE
);
633 if (!NT_SUCCESS(Status
)) return FALSE
;
635 /* Open the symbolic link for it */
636 InitializeObjectAttributes(&ObjectAttributes
,
638 OBJ_CASE_INSENSITIVE
,
641 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
642 SYMBOLIC_LINK_ALL_ACCESS
,
644 if (!NT_SUCCESS(Status
)) return FALSE
;
647 NtMakeTemporaryObject(LinkHandle
);
648 ObCloseHandle(LinkHandle
, KernelMode
);
650 /* Now create the new name for it */
651 sprintf(Buffer
, "%s%s", ArcString
.Buffer
, LoaderBlock
->NtBootPathName
);
653 /* Copy it into the passed parameter and null-terminate it */
654 RtlCopyString(NtBootPath
, &ArcString
);
655 Buffer
[strlen(Buffer
) - 1] = ANSI_NULL
;
657 /* Setup the Unicode-name for the new symbolic link value */
658 RtlInitAnsiString(&TargetString
, Buffer
);
659 InitializeObjectAttributes(&ObjectAttributes
,
661 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
664 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TargetString
, TRUE
);
665 if (!NT_SUCCESS(Status
)) return FALSE
;
668 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
669 SYMBOLIC_LINK_ALL_ACCESS
,
673 /* Free all the strings and close the handle and return success */
674 RtlFreeUnicodeString(&ArcName
);
675 RtlFreeUnicodeString(&LinkName
);
676 ObCloseHandle(LinkHandle
, KernelMode
);