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
;
36 PCONFIGURATION_INFORMATION ConfigInfo
= IoGetConfigurationInformation();
37 extern BOOLEAN InitIsWinPEMode
, ExpInTextModeSetup
;
39 /* Only ARC Name left - Build full ARC Name */
40 p
= strstr(KeLoaderBlock
->ArcBootDeviceName
, "cdrom");
43 /* Build installer name */
44 sprintf(Buffer
, "\\Device\\CdRom%lu\\reactos\\ntoskrnl.exe", i
);
45 RtlInitAnsiString(&InstallName
, Buffer
);
46 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &InstallName
, TRUE
);
47 if (!NT_SUCCESS(Status
)) return FALSE
;
49 /* Try to find the installer */
50 InitializeObjectAttributes(&ObjectAttributes
,
55 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
58 RtlFreeUnicodeString(&DeviceName
);
60 /* Check if we found the file */
61 if (NT_SUCCESS(Status
))
63 /* We did, save the device number */
68 /* Build live CD kernel name */
70 "\\Device\\CdRom%lu\\reactos\\system32\\ntoskrnl.exe",
72 RtlInitAnsiString(&InstallName
, Buffer
);
73 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
76 if (!NT_SUCCESS(Status
)) return FALSE
;
79 InitializeObjectAttributes(&ObjectAttributes
,
84 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
85 if (NT_SUCCESS(Status
)) DeviceNumber
= i
;
88 RtlFreeUnicodeString(&DeviceName
);
94 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
96 /* Adjust original command line */
102 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
108 /* OK, how many disks are there? */
109 DeviceNumber
+= ConfigInfo
->DiskCount
;
111 /* Return whether this is the CD or not */
112 if ((InitIsWinPEMode
) || (ExpInTextModeSetup
))
114 /* Hack until IoAssignDriveLetters is fixed */
115 swprintf(SharedUserData
->NtSystemRoot
, L
"%c:\\reactos", 'C' + DeviceNumber
);
126 IopGetDiskInformation(IN ULONG i
,
128 OUT PULONG Signature
,
129 OUT PULONG PartitionCount
,
130 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
133 ANSI_STRING TempString
;
135 UNICODE_STRING DeviceName
;
137 PDEVICE_OBJECT DeviceObject
;
138 PFILE_OBJECT FileObject
;
139 DISK_GEOMETRY DiskGeometry
;
140 PDRIVE_LAYOUT_INFORMATION DriveLayout
;
143 IO_STATUS_BLOCK StatusBlock
;
144 LARGE_INTEGER PartitionOffset
;
145 PULONG PartitionBuffer
;
148 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
150 /* Convert it to Unicode */
151 RtlInitAnsiString(&TempString
, Buffer
);
152 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
153 if (!NT_SUCCESS(Status
)) return FALSE
;
155 /* Get the device pointer */
156 Status
= IoGetDeviceObjectPointer(&DeviceName
,
157 FILE_READ_ATTRIBUTES
,
160 *DiskDeviceObject
= DeviceObject
;
162 /* Free the string */
163 RtlFreeUnicodeString(&DeviceName
);
165 /* Move on if we failed */
166 if (!NT_SUCCESS(Status
)) return FALSE
;
168 /* Build an IRP to determine the sector size */
169 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
170 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
175 sizeof(DISK_GEOMETRY
),
182 ObDereferenceObject(FileObject
);
186 /* Call the driver and check if we have to wait on it */
187 Status
= IoCallDriver(DeviceObject
, Irp
);
188 if (Status
== STATUS_PENDING
)
190 /* Wait on the driver */
191 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
192 Status
= StatusBlock
.Status
;
195 /* Check if we failed */
196 if (!NT_SUCCESS(Status
))
199 ObDereferenceObject(FileObject
);
203 /* Read the partition table */
204 Status
= IoReadPartitionTable(DeviceObject
,
205 DiskGeometry
.BytesPerSector
,
209 /* Dereference the file object */
210 ObDereferenceObject(FileObject
);
211 if (!NT_SUCCESS(Status
)) return FALSE
;
213 /* Set the offset to 0 */
214 PartitionOffset
.QuadPart
= 0;
216 /* Allocate a buffer for the partition */
217 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
218 DiskGeometry
.BytesPerSector
,
220 if (!PartitionBuffer
)
223 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
227 /* Build an IRP to read the partition sector */
228 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
229 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
232 DiskGeometry
.BytesPerSector
,
239 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
240 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
244 /* Call the driver and check if we have to wait */
245 Status
= IoCallDriver(DeviceObject
, Irp
);
246 if (Status
== STATUS_PENDING
)
248 /* Wait for completion */
249 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
250 Status
= StatusBlock
.Status
;
253 /* Check if we failed */
254 if (!NT_SUCCESS(Status
))
257 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
258 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
262 /* Calculate the MBR checksum */
264 for (j
= 0; j
< 128; j
++) Checksum
+= PartitionBuffer
[j
];
266 /* Save the signature and checksum */
267 *CheckSum
= ~Checksum
+ 1;
268 *Signature
= DriveLayout
->Signature
;
269 *PartitionCount
= DriveLayout
->PartitionCount
;
271 /* Free the buffer */
272 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
273 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
280 IopAssignArcNamesToCdrom(IN PULONG Buffer
,
284 ANSI_STRING TempString
;
285 UNICODE_STRING DeviceName
, ArcName
;
287 LARGE_INTEGER PartitionOffset
;
289 IO_STATUS_BLOCK IoStatusBlock
;
291 ULONG i
, CheckSum
= 0;
292 PDEVICE_OBJECT DeviceObject
;
293 PFILE_OBJECT FileObject
;
295 /* Build the device name */
296 sprintf(ArcBuffer
, "\\Device\\CdRom%lu", DiskNumber
);
298 /* Convert it to Unicode */
299 RtlInitAnsiString(&TempString
, ArcBuffer
);
300 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
301 if (!NT_SUCCESS(Status
)) return FALSE
;
303 /* Get the device for it */
304 Status
= IoGetDeviceObjectPointer(&DeviceName
,
305 FILE_READ_ATTRIBUTES
,
308 if (!NT_SUCCESS(Status
))
310 /* Free the string and fail */
311 RtlFreeUnicodeString(&DeviceName
);
315 /* Setup the event */
316 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
318 /* Set the offset and build the read IRP */
319 PartitionOffset
.QuadPart
= 0x8000;
320 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
329 /* Free the string and fail */
330 RtlFreeUnicodeString(&DeviceName
);
334 /* Call the driver and check if we have to wait on it */
335 Status
= IoCallDriver(DeviceObject
, Irp
);
336 if (Status
== STATUS_PENDING
)
338 /* Wait for completion */
339 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
340 Status
= IoStatusBlock
.Status
;
343 /* Dereference the file object */
344 ObDereferenceObject(FileObject
);
345 if (!NT_SUCCESS(Status
)) return FALSE
;
347 /* Now calculate the checksum */
348 for (i
= 0; i
< 2048 / sizeof(ULONG
); i
++) CheckSum
+= Buffer
[i
];
351 * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
352 * ARC Path name, and what happens here is a comparision of both checksums
353 * in order to see if this is the actual boot CD.
355 * In ReactOS this doesn't currently happen, instead we have a hack on top
356 * of this file which scans the CD for the ntoskrnl.exe file, then modifies
357 * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
358 * get the same state as if NTLDR had properly booted us, except that we do
359 * not actually need to check the signature, since the hack already did the
360 * check for ntoskrnl.exe, which is just as good.
362 * The signature code stays however, because eventually FreeLDR will work
363 * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
365 if (IopApplyRosCdromArcHack(DiskNumber
))
367 /* This is the boot CD-ROM, build the ARC name */
368 sprintf(ArcBuffer
, "\\ArcName\\%s", KeLoaderBlock
->ArcBootDeviceName
);
370 /* Convert it to Unicode */
371 RtlInitAnsiString(&TempString
, ArcBuffer
);
372 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TempString
, TRUE
);
373 if (!NT_SUCCESS(Status
)) return FALSE
;
375 /* Create the symbolic link and free the strings */
376 IoAssignArcName(&ArcName
, &DeviceName
);
377 RtlFreeUnicodeString(&ArcName
);
378 RtlFreeUnicodeString(&DeviceName
);
380 /* Let caller know that we've found the boot CD */
384 /* No boot CD found */
391 IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
393 PCONFIGURATION_INFORMATION ConfigInfo
= IoGetConfigurationInformation();
394 PARC_DISK_INFORMATION ArcDiskInfo
= LoaderBlock
->ArcDiskInformation
;
396 ANSI_STRING ArcBootString
, ArcSystemString
, ArcString
;
397 UNICODE_STRING ArcName
, BootPath
, DeviceName
;
400 PDEVICE_OBJECT DeviceObject
;
401 ULONG Signature
, Checksum
, PartitionCount
;
402 PLIST_ENTRY NextEntry
;
403 PARC_DISK_SIGNATURE ArcDiskEntry
;
405 BOOLEAN FoundBoot
= FALSE
;
406 PULONG PartitionBuffer
;
408 /* Check if we only have one disk on the machine */
409 SingleDisk
= ArcDiskInfo
->DiskSignatureListHead
.Flink
->Flink
==
410 (&ArcDiskInfo
->DiskSignatureListHead
);
412 /* Create the global HAL partition name */
413 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcHalDeviceName
);
414 RtlInitAnsiString(&ArcString
, Buffer
);
415 RtlAnsiStringToUnicodeString(&IoArcHalDeviceName
, &ArcString
, TRUE
);
417 /* Create the global system partition name */
418 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
419 RtlInitAnsiString(&ArcString
, Buffer
);
420 RtlAnsiStringToUnicodeString(&IoArcBootDeviceName
, &ArcString
, TRUE
);
422 /* Allocate memory for the string */
423 Length
= strlen(LoaderBlock
->ArcBootDeviceName
) + sizeof(ANSI_NULL
);
424 IoLoaderArcBootDeviceName
= ExAllocatePoolWithTag(PagedPool
,
427 if (IoLoaderArcBootDeviceName
)
430 RtlCopyMemory(IoLoaderArcBootDeviceName
,
431 LoaderBlock
->ArcBootDeviceName
,
435 /* Check if we only found a disk, but we're booting from CD-ROM */
436 if ((SingleDisk
) && strstr(LoaderBlock
->ArcBootDeviceName
, "cdrom"))
438 /* Then disable single-disk mode, since there's a CD drive out there */
442 /* Build the boot strings */
443 RtlInitAnsiString(&ArcBootString
, LoaderBlock
->ArcBootDeviceName
);
444 RtlInitAnsiString(&ArcSystemString
, LoaderBlock
->ArcHalDeviceName
);
446 /* Loop every detected disk */
447 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
449 /* Get information about the disk */
450 if (!IopGetDiskInformation(i
,
461 for (NextEntry
= ArcDiskInfo
->DiskSignatureListHead
.Flink
;
462 NextEntry
!= &ArcDiskInfo
->DiskSignatureListHead
;
463 NextEntry
= NextEntry
->Flink
)
465 /* Get the current ARC disk signature entry */
466 ArcDiskEntry
= CONTAINING_RECORD(NextEntry
,
471 * Now check if the signature and checksum match, unless this is
472 * the only disk that was in the ARC list, and also in the device
473 * tree, in which case the check is bypassed and we accept the disk
475 if (((SingleDisk
) && (ConfigInfo
->DiskCount
== 1)) ||
476 ((Checksum
== ArcDiskEntry
->CheckSum
) &&
477 (Signature
== ArcDiskEntry
->Signature
)))
479 /* Build the NT Device Name */
480 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
482 /* Convert it to Unicode */
483 RtlInitAnsiString(&ArcString
, Buffer
);
484 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
487 if (!NT_SUCCESS(Status
)) continue;
489 /* Build the ARC Device Name */
490 sprintf(Buffer
, "\\ArcName\\%s", ArcDiskEntry
->ArcName
);
492 /* Convert it to Unicode */
493 RtlInitAnsiString(&ArcString
, Buffer
);
494 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
497 if (!NT_SUCCESS(Status
)) continue;
499 /* Create the symbolic link and free the strings */
500 IoAssignArcName(&ArcName
, &DeviceName
);
501 RtlFreeUnicodeString(&ArcName
);
502 RtlFreeUnicodeString(&DeviceName
);
504 /* Loop all the partitions */
505 for (j
= 0; j
< PartitionCount
; j
++)
507 /* Build the partition device name */
509 "\\Device\\Harddisk%lu\\Partition%lu",
513 /* Convert it to Unicode */
514 RtlInitAnsiString(&ArcString
, Buffer
);
515 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
518 if (!NT_SUCCESS(Status
)) continue;
520 /* Build the partial ARC name for this partition */
523 ArcDiskEntry
->ArcName
,
525 RtlInitAnsiString(&ArcString
, Buffer
);
527 /* Check if this is the boot device */
528 if (RtlEqualString(&ArcString
, &ArcBootString
, TRUE
))
530 /* Remember that we found a Hard Disk Boot Device */
534 /* Check if it's the system boot partition */
535 if (RtlEqualString(&ArcString
, &ArcSystemString
, TRUE
))
537 /* It is, create a Unicode string for it */
538 RtlInitAnsiString(&ArcString
,
539 LoaderBlock
->NtHalPathName
);
540 Status
= RtlAnsiStringToUnicodeString(&BootPath
,
543 if (NT_SUCCESS(Status
))
545 /* FIXME: Save in registry */
547 /* Free the string now */
548 RtlFreeUnicodeString(&BootPath
);
552 /* Build the full ARC name */
554 "\\ArcName\\%spartition(%lu)",
555 ArcDiskEntry
->ArcName
,
558 /* Convert it to Unicode */
559 RtlInitAnsiString(&ArcString
, Buffer
);
560 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
563 if (!NT_SUCCESS(Status
)) continue;
565 /* Create the symbolic link and free the strings */
566 IoAssignArcName(&ArcName
, &DeviceName
);
567 RtlFreeUnicodeString(&ArcName
);
568 RtlFreeUnicodeString(&DeviceName
);
574 /* Check if we didn't find the boot disk */
577 /* Allocate a buffer for the CD-ROM MBR */
578 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
, 2048, TAG_IO
);
579 if (!PartitionBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
581 /* Loop every CD-ROM */
582 for (i
= 0; i
< ConfigInfo
->CdRomCount
; i
++)
584 /* Give it an ARC name */
585 if (IopAssignArcNamesToCdrom(PartitionBuffer
, i
)) break;
588 /* Free the buffer */
589 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
593 return STATUS_SUCCESS
;
598 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
599 OUT PANSI_STRING NtBootPath
)
601 OBJECT_ATTRIBUTES ObjectAttributes
;
603 CHAR Buffer
[256], AnsiBuffer
[256];
604 WCHAR ArcNameBuffer
[64];
605 ANSI_STRING TargetString
, ArcString
, TempString
;
606 UNICODE_STRING LinkName
, TargetName
, ArcName
;
609 /* Create the Unicode name for the current ARC boot device */
610 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
611 RtlInitAnsiString(&TargetString
, Buffer
);
612 Status
= RtlAnsiStringToUnicodeString(&TargetName
, &TargetString
, TRUE
);
613 if (!NT_SUCCESS(Status
)) return FALSE
;
615 /* Initialize the attributes and open the link */
616 InitializeObjectAttributes(&ObjectAttributes
,
618 OBJ_CASE_INSENSITIVE
,
621 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
622 SYMBOLIC_LINK_ALL_ACCESS
,
624 if (!NT_SUCCESS(Status
))
626 /* We failed, free the string */
627 RtlFreeUnicodeString(&TargetName
);
631 /* Query the current \\SystemRoot */
632 ArcName
.Buffer
= ArcNameBuffer
;
634 ArcName
.MaximumLength
= sizeof(ArcNameBuffer
);
635 Status
= NtQuerySymbolicLinkObject(LinkHandle
, &ArcName
, NULL
);
636 if (!NT_SUCCESS(Status
))
638 /* We failed, free the string */
639 RtlFreeUnicodeString(&TargetName
);
643 /* Convert it to Ansi */
644 ArcString
.Buffer
= AnsiBuffer
;
645 ArcString
.Length
= 0;
646 ArcString
.MaximumLength
= sizeof(AnsiBuffer
);
647 Status
= RtlUnicodeStringToAnsiString(&ArcString
, &ArcName
, FALSE
);
648 AnsiBuffer
[ArcString
.Length
] = ANSI_NULL
;
650 /* Close the link handle and free the name */
651 ObCloseHandle(LinkHandle
, KernelMode
);
652 RtlFreeUnicodeString(&TargetName
);
654 /* Setup the system root name again */
655 RtlInitAnsiString(&TempString
, "\\SystemRoot");
656 Status
= RtlAnsiStringToUnicodeString(&LinkName
, &TempString
, TRUE
);
657 if (!NT_SUCCESS(Status
)) return FALSE
;
659 /* Open the symbolic link for it */
660 InitializeObjectAttributes(&ObjectAttributes
,
662 OBJ_CASE_INSENSITIVE
,
665 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
666 SYMBOLIC_LINK_ALL_ACCESS
,
668 if (!NT_SUCCESS(Status
)) return FALSE
;
671 NtMakeTemporaryObject(LinkHandle
);
672 ObCloseHandle(LinkHandle
, KernelMode
);
674 /* Now create the new name for it */
675 sprintf(Buffer
, "%s%s", ArcString
.Buffer
, LoaderBlock
->NtBootPathName
);
677 /* Copy it into the passed parameter and null-terminate it */
678 RtlCopyString(NtBootPath
, &ArcString
);
679 Buffer
[strlen(Buffer
) - 1] = ANSI_NULL
;
681 /* Setup the Unicode-name for the new symbolic link value */
682 RtlInitAnsiString(&TargetString
, Buffer
);
683 InitializeObjectAttributes(&ObjectAttributes
,
685 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
688 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TargetString
, TRUE
);
689 if (!NT_SUCCESS(Status
)) return FALSE
;
692 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
693 SYMBOLIC_LINK_ALL_ACCESS
,
697 /* Free all the strings and close the handle and return success */
698 RtlFreeUnicodeString(&ArcName
);
699 RtlFreeUnicodeString(&LinkName
);
700 ObCloseHandle(LinkHandle
, KernelMode
);