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
;
32 CHAR Buffer
[128], RosSysPath
[16];
33 FILE_BASIC_INFORMATION FileInfo
;
36 PCONFIGURATION_INFORMATION ConfigInfo
= IoGetConfigurationInformation();
37 extern BOOLEAN InitIsWinPEMode
, ExpInTextModeSetup
;
39 /* Change this if you want ROS to boot properly from another directory */
40 sprintf(RosSysPath
, "%s", "reactos");
42 /* Only ARC Name left - Build full ARC Name */
43 p
= strstr(KeLoaderBlock
->ArcBootDeviceName
, "cdrom");
46 /* Build installer name */
47 sprintf(Buffer
, "\\Device\\CdRom%lu\\%s\\ntoskrnl.exe", i
, RosSysPath
);
48 RtlInitAnsiString(&InstallName
, Buffer
);
49 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &InstallName
, TRUE
);
50 if (!NT_SUCCESS(Status
)) return FALSE
;
52 /* Try to find the installer */
53 InitializeObjectAttributes(&ObjectAttributes
,
58 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
61 RtlFreeUnicodeString(&DeviceName
);
63 /* Check if we found the file */
64 if (NT_SUCCESS(Status
))
66 /* We did, save the device number */
71 /* Build live CD kernel name */
73 "\\Device\\CdRom%lu\\%s\\system32\\ntoskrnl.exe",
75 RtlInitAnsiString(&InstallName
, Buffer
);
76 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
79 if (!NT_SUCCESS(Status
)) return FALSE
;
82 InitializeObjectAttributes(&ObjectAttributes
,
87 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
88 if (NT_SUCCESS(Status
)) DeviceNumber
= i
;
91 RtlFreeUnicodeString(&DeviceName
);
97 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
99 /* Adjust original command line */
105 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
111 /* OK, how many disks are there? */
112 DeviceNumber
+= ConfigInfo
->DiskCount
;
114 /* Return whether this is the CD or not */
115 if ((InitIsWinPEMode
) || (ExpInTextModeSetup
))
127 IopGetDiskInformation(IN ULONG i
,
129 OUT PULONG Signature
,
130 OUT PULONG PartitionCount
,
131 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
134 ANSI_STRING TempString
;
136 UNICODE_STRING DeviceName
;
138 PDEVICE_OBJECT DeviceObject
;
139 PFILE_OBJECT FileObject
;
140 DISK_GEOMETRY DiskGeometry
;
141 PDRIVE_LAYOUT_INFORMATION DriveLayout
;
144 IO_STATUS_BLOCK StatusBlock
;
145 LARGE_INTEGER PartitionOffset
;
146 PULONG PartitionBuffer
;
149 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
151 /* Convert it to Unicode */
152 RtlInitAnsiString(&TempString
, Buffer
);
153 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
154 if (!NT_SUCCESS(Status
)) return FALSE
;
156 /* Get the device pointer */
157 Status
= IoGetDeviceObjectPointer(&DeviceName
,
158 FILE_READ_ATTRIBUTES
,
161 *DiskDeviceObject
= DeviceObject
;
163 /* Free the string */
164 RtlFreeUnicodeString(&DeviceName
);
166 /* Move on if we failed */
167 if (!NT_SUCCESS(Status
)) return FALSE
;
169 /* Build an IRP to determine the sector size */
170 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
171 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
176 sizeof(DISK_GEOMETRY
),
183 ObDereferenceObject(FileObject
);
187 /* Call the driver and check if we have to wait on it */
188 Status
= IoCallDriver(DeviceObject
, Irp
);
189 if (Status
== STATUS_PENDING
)
191 /* Wait on the driver */
192 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
193 Status
= StatusBlock
.Status
;
196 /* Check if we failed */
197 if (!NT_SUCCESS(Status
))
200 ObDereferenceObject(FileObject
);
204 /* Read the partition table */
205 Status
= IoReadPartitionTable(DeviceObject
,
206 DiskGeometry
.BytesPerSector
,
210 /* Dereference the file object */
211 ObDereferenceObject(FileObject
);
212 if (!NT_SUCCESS(Status
)) return FALSE
;
214 /* Set the offset to 0 */
215 PartitionOffset
.QuadPart
= 0;
217 /* Allocate a buffer for the partition */
218 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
219 DiskGeometry
.BytesPerSector
,
221 if (!PartitionBuffer
)
224 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
228 /* Build an IRP to read the partition sector */
229 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
230 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
233 DiskGeometry
.BytesPerSector
,
240 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
241 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
245 /* Call the driver and check if we have to wait */
246 Status
= IoCallDriver(DeviceObject
, Irp
);
247 if (Status
== STATUS_PENDING
)
249 /* Wait for completion */
250 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
251 Status
= StatusBlock
.Status
;
254 /* Check if we failed */
255 if (!NT_SUCCESS(Status
))
258 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
259 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
263 /* Calculate the MBR checksum */
265 for (j
= 0; j
< 128; j
++) Checksum
+= PartitionBuffer
[j
];
267 /* Save the signature and checksum */
268 *CheckSum
= ~Checksum
+ 1;
269 *Signature
= DriveLayout
->Signature
;
270 *PartitionCount
= DriveLayout
->PartitionCount
;
272 /* Free the buffer */
273 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
274 ExFreePoolWithTag(DriveLayout
, TAG_FILE_SYSTEM
);
281 IopAssignArcNamesToCdrom(IN PULONG Buffer
,
285 ANSI_STRING TempString
;
286 UNICODE_STRING DeviceName
, ArcName
;
288 LARGE_INTEGER PartitionOffset
;
290 IO_STATUS_BLOCK IoStatusBlock
;
292 ULONG i
, CheckSum
= 0;
293 PDEVICE_OBJECT DeviceObject
;
294 PFILE_OBJECT FileObject
;
296 /* Build the device name */
297 sprintf(ArcBuffer
, "\\Device\\CdRom%lu", DiskNumber
);
299 /* Convert it to Unicode */
300 RtlInitAnsiString(&TempString
, ArcBuffer
);
301 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
302 if (!NT_SUCCESS(Status
)) return FALSE
;
304 /* Get the device for it */
305 Status
= IoGetDeviceObjectPointer(&DeviceName
,
306 FILE_READ_ATTRIBUTES
,
309 if (!NT_SUCCESS(Status
))
311 /* Free the string and fail */
312 RtlFreeUnicodeString(&DeviceName
);
316 /* Setup the event */
317 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
319 /* Set the offset and build the read IRP */
320 PartitionOffset
.QuadPart
= 0x8000;
321 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
330 /* Free the string and fail */
331 RtlFreeUnicodeString(&DeviceName
);
335 /* Call the driver and check if we have to wait on it */
336 Status
= IoCallDriver(DeviceObject
, Irp
);
337 if (Status
== STATUS_PENDING
)
339 /* Wait for completion */
340 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
341 Status
= IoStatusBlock
.Status
;
344 /* Dereference the file object */
345 ObDereferenceObject(FileObject
);
346 if (!NT_SUCCESS(Status
)) return FALSE
;
348 /* Now calculate the checksum */
349 for (i
= 0; i
< 2048 / sizeof(ULONG
); i
++) CheckSum
+= Buffer
[i
];
352 * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
353 * ARC Path name, and what happens here is a comparision of both checksums
354 * in order to see if this is the actual boot CD.
356 * In ReactOS this doesn't currently happen, instead we have a hack on top
357 * of this file which scans the CD for the ntoskrnl.exe file, then modifies
358 * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
359 * get the same state as if NTLDR had properly booted us, except that we do
360 * not actually need to check the signature, since the hack already did the
361 * check for ntoskrnl.exe, which is just as good.
363 * The signature code stays however, because eventually FreeLDR will work
364 * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
366 if (IopApplyRosCdromArcHack(DiskNumber
))
368 /* This is the boot CD-ROM, build the ARC name */
369 sprintf(ArcBuffer
, "\\ArcName\\%s", KeLoaderBlock
->ArcBootDeviceName
);
371 /* Convert it to Unicode */
372 RtlInitAnsiString(&TempString
, ArcBuffer
);
373 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TempString
, TRUE
);
374 if (!NT_SUCCESS(Status
)) return FALSE
;
376 /* Create the symbolic link and free the strings */
377 IoAssignArcName(&ArcName
, &DeviceName
);
378 RtlFreeUnicodeString(&ArcName
);
379 RtlFreeUnicodeString(&DeviceName
);
381 /* Let caller know that we've found the boot CD */
385 /* No boot CD found */
392 IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
394 PCONFIGURATION_INFORMATION ConfigInfo
= IoGetConfigurationInformation();
395 PARC_DISK_INFORMATION ArcDiskInfo
= LoaderBlock
->ArcDiskInformation
;
397 ANSI_STRING ArcBootString
, ArcSystemString
, ArcString
;
398 UNICODE_STRING ArcName
, BootPath
, DeviceName
;
401 PDEVICE_OBJECT DeviceObject
;
402 ULONG Signature
, Checksum
, PartitionCount
;
403 PLIST_ENTRY NextEntry
;
404 PARC_DISK_SIGNATURE ArcDiskEntry
;
406 BOOLEAN FoundBoot
= FALSE
;
407 PULONG PartitionBuffer
;
409 /* Check if we only have one disk on the machine */
410 SingleDisk
= ArcDiskInfo
->DiskSignatureListHead
.Flink
->Flink
==
411 (&ArcDiskInfo
->DiskSignatureListHead
);
413 /* Create the global HAL partition name */
414 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcHalDeviceName
);
415 RtlInitAnsiString(&ArcString
, Buffer
);
416 RtlAnsiStringToUnicodeString(&IoArcHalDeviceName
, &ArcString
, TRUE
);
418 /* Create the global system partition name */
419 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
420 RtlInitAnsiString(&ArcString
, Buffer
);
421 RtlAnsiStringToUnicodeString(&IoArcBootDeviceName
, &ArcString
, TRUE
);
423 /* Allocate memory for the string */
424 Length
= strlen(LoaderBlock
->ArcBootDeviceName
) + sizeof(ANSI_NULL
);
425 IoLoaderArcBootDeviceName
= ExAllocatePoolWithTag(PagedPool
,
428 if (IoLoaderArcBootDeviceName
)
431 RtlCopyMemory(IoLoaderArcBootDeviceName
,
432 LoaderBlock
->ArcBootDeviceName
,
436 /* Check if we only found a disk, but we're booting from CD-ROM */
437 if ((SingleDisk
) && strstr(LoaderBlock
->ArcBootDeviceName
, "cdrom"))
439 /* Then disable single-disk mode, since there's a CD drive out there */
443 /* Build the boot strings */
444 RtlInitAnsiString(&ArcBootString
, LoaderBlock
->ArcBootDeviceName
);
445 RtlInitAnsiString(&ArcSystemString
, LoaderBlock
->ArcHalDeviceName
);
447 /* Loop every detected disk */
448 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
450 /* Get information about the disk */
451 if (!IopGetDiskInformation(i
,
462 for (NextEntry
= ArcDiskInfo
->DiskSignatureListHead
.Flink
;
463 NextEntry
!= &ArcDiskInfo
->DiskSignatureListHead
;
464 NextEntry
= NextEntry
->Flink
)
466 /* Get the current ARC disk signature entry */
467 ArcDiskEntry
= CONTAINING_RECORD(NextEntry
,
472 * Now check if the signature and checksum match, unless this is
473 * the only disk that was in the ARC list, and also in the device
474 * tree, in which case the check is bypassed and we accept the disk
476 if (((SingleDisk
) && (ConfigInfo
->DiskCount
== 1)) ||
477 ((Checksum
== ArcDiskEntry
->CheckSum
) &&
478 (Signature
== ArcDiskEntry
->Signature
)))
480 /* Build the NT Device Name */
481 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
483 /* Convert it to Unicode */
484 RtlInitAnsiString(&ArcString
, Buffer
);
485 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
488 if (!NT_SUCCESS(Status
)) continue;
490 /* Build the ARC Device Name */
491 sprintf(Buffer
, "\\ArcName\\%s", ArcDiskEntry
->ArcName
);
493 /* Convert it to Unicode */
494 RtlInitAnsiString(&ArcString
, Buffer
);
495 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
498 if (!NT_SUCCESS(Status
)) continue;
500 /* Create the symbolic link and free the strings */
501 IoAssignArcName(&ArcName
, &DeviceName
);
502 RtlFreeUnicodeString(&ArcName
);
503 RtlFreeUnicodeString(&DeviceName
);
505 /* Loop all the partitions */
506 for (j
= 0; j
< PartitionCount
; j
++)
508 /* Build the partition device name */
510 "\\Device\\Harddisk%lu\\Partition%lu",
514 /* Convert it to Unicode */
515 RtlInitAnsiString(&ArcString
, Buffer
);
516 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
519 if (!NT_SUCCESS(Status
)) continue;
521 /* Build the partial ARC name for this partition */
524 ArcDiskEntry
->ArcName
,
526 RtlInitAnsiString(&ArcString
, Buffer
);
528 /* Check if this is the boot device */
529 if (RtlEqualString(&ArcString
, &ArcBootString
, TRUE
))
531 /* Remember that we found a Hard Disk Boot Device */
535 /* Check if it's the system boot partition */
536 if (RtlEqualString(&ArcString
, &ArcSystemString
, TRUE
))
538 /* It is, create a Unicode string for it */
539 RtlInitAnsiString(&ArcString
,
540 LoaderBlock
->NtHalPathName
);
541 Status
= RtlAnsiStringToUnicodeString(&BootPath
,
544 if (NT_SUCCESS(Status
))
546 /* FIXME: Save in registry */
548 /* Free the string now */
549 RtlFreeUnicodeString(&BootPath
);
553 /* Build the full ARC name */
555 "\\ArcName\\%spartition(%lu)",
556 ArcDiskEntry
->ArcName
,
559 /* Convert it to Unicode */
560 RtlInitAnsiString(&ArcString
, Buffer
);
561 Status
= RtlAnsiStringToUnicodeString(&ArcName
,
564 if (!NT_SUCCESS(Status
)) continue;
566 /* Create the symbolic link and free the strings */
567 IoAssignArcName(&ArcName
, &DeviceName
);
568 RtlFreeUnicodeString(&ArcName
);
569 RtlFreeUnicodeString(&DeviceName
);
575 /* Check if we didn't find the boot disk */
578 /* Allocate a buffer for the CD-ROM MBR */
579 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
, 2048, TAG_IO
);
580 if (!PartitionBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
582 /* Loop every CD-ROM */
583 for (i
= 0; i
< ConfigInfo
->CdRomCount
; i
++)
585 /* Give it an ARC name */
586 if (IopAssignArcNamesToCdrom(PartitionBuffer
, i
)) break;
589 /* Free the buffer */
590 ExFreePoolWithTag(PartitionBuffer
, TAG_IO
);
594 return STATUS_SUCCESS
;
599 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
600 OUT PANSI_STRING NtBootPath
)
602 OBJECT_ATTRIBUTES ObjectAttributes
;
604 CHAR Buffer
[256], AnsiBuffer
[256];
605 WCHAR ArcNameBuffer
[64];
606 ANSI_STRING TargetString
, ArcString
, TempString
;
607 UNICODE_STRING LinkName
, TargetName
, ArcName
;
610 /* Create the Unicode name for the current ARC boot device */
611 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
612 RtlInitAnsiString(&TargetString
, Buffer
);
613 Status
= RtlAnsiStringToUnicodeString(&TargetName
, &TargetString
, TRUE
);
614 if (!NT_SUCCESS(Status
)) return FALSE
;
616 /* Initialize the attributes and open the link */
617 InitializeObjectAttributes(&ObjectAttributes
,
619 OBJ_CASE_INSENSITIVE
,
622 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
623 SYMBOLIC_LINK_ALL_ACCESS
,
625 if (!NT_SUCCESS(Status
))
627 /* We failed, free the string */
628 RtlFreeUnicodeString(&TargetName
);
632 /* Query the current \\SystemRoot */
633 ArcName
.Buffer
= ArcNameBuffer
;
635 ArcName
.MaximumLength
= sizeof(ArcNameBuffer
);
636 Status
= NtQuerySymbolicLinkObject(LinkHandle
, &ArcName
, NULL
);
637 if (!NT_SUCCESS(Status
))
639 /* We failed, free the string */
640 RtlFreeUnicodeString(&TargetName
);
644 /* Convert it to Ansi */
645 ArcString
.Buffer
= AnsiBuffer
;
646 ArcString
.Length
= 0;
647 ArcString
.MaximumLength
= sizeof(AnsiBuffer
);
648 Status
= RtlUnicodeStringToAnsiString(&ArcString
, &ArcName
, FALSE
);
649 AnsiBuffer
[ArcString
.Length
] = ANSI_NULL
;
651 /* Close the link handle and free the name */
652 ObCloseHandle(LinkHandle
, KernelMode
);
653 RtlFreeUnicodeString(&TargetName
);
655 /* Setup the system root name again */
656 RtlInitAnsiString(&TempString
, "\\SystemRoot");
657 Status
= RtlAnsiStringToUnicodeString(&LinkName
, &TempString
, TRUE
);
658 if (!NT_SUCCESS(Status
)) return FALSE
;
660 /* Open the symbolic link for it */
661 InitializeObjectAttributes(&ObjectAttributes
,
663 OBJ_CASE_INSENSITIVE
,
666 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
667 SYMBOLIC_LINK_ALL_ACCESS
,
669 if (!NT_SUCCESS(Status
)) return FALSE
;
672 NtMakeTemporaryObject(LinkHandle
);
673 ObCloseHandle(LinkHandle
, KernelMode
);
675 /* Now create the new name for it */
676 sprintf(Buffer
, "%s%s", ArcString
.Buffer
, LoaderBlock
->NtBootPathName
);
678 /* Copy it into the passed parameter and null-terminate it */
679 RtlCopyString(NtBootPath
, &ArcString
);
680 Buffer
[strlen(Buffer
) - 1] = ANSI_NULL
;
682 /* Setup the Unicode-name for the new symbolic link value */
683 RtlInitAnsiString(&TargetString
, Buffer
);
684 InitializeObjectAttributes(&ObjectAttributes
,
686 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
689 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TargetString
, TRUE
);
690 if (!NT_SUCCESS(Status
)) return FALSE
;
693 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
694 SYMBOLIC_LINK_ALL_ACCESS
,
698 /* Free all the strings and close the handle and return success */
699 RtlFreeUnicodeString(&ArcName
);
700 RtlFreeUnicodeString(&LinkName
);
701 ObCloseHandle(LinkHandle
, KernelMode
);