3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/arcname.c
6 * PURPOSE: Creates ARC names for boot devices
8 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
11 /* INCLUDES *****************************************************************/
17 /* GLOBALS *******************************************************************/
19 UNICODE_STRING IoArcHalDeviceName
, IoArcBootDeviceName
;
20 PCHAR IoLoaderArcBootDeviceName
;
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
[MAX_PATH
];
34 FILE_BASIC_INFORMATION FileInfo
;
38 /* Only ARC Name left - Build full ARC Name */
39 p
= strstr(KeLoaderBlock
->ArcBootDeviceName
, "cdrom");
42 /* Build installer name */
43 sprintf(Buffer
, "\\Device\\CdRom%lu\\reactos\\ntoskrnl.exe", i
);
44 RtlInitAnsiString(&InstallName
, Buffer
);
45 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &InstallName
, TRUE
);
46 if (!NT_SUCCESS(Status
)) return FALSE
;
48 /* Try to find the installer */
49 InitializeObjectAttributes(&ObjectAttributes
,
54 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
57 RtlFreeUnicodeString(&DeviceName
);
59 /* Check if we found the file */
60 if (NT_SUCCESS(Status
))
62 /* We did, save the device number */
67 /* Build live CD kernel name */
69 "\\Device\\CdRom%lu\\reactos\\system32\\ntoskrnl.exe",
71 RtlInitAnsiString(&InstallName
, Buffer
);
72 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
75 if (!NT_SUCCESS(Status
)) return FALSE
;
78 InitializeObjectAttributes(&ObjectAttributes
,
83 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
84 if (NT_SUCCESS(Status
)) DeviceNumber
= i
;
87 RtlFreeUnicodeString(&DeviceName
);
91 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
93 /* Adjust original command line */
99 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
104 /* Return whether this is the CD or not */
105 if (DeviceNumber
!= 1) return TRUE
;
112 IopGetDiskInformation(IN ULONG i
,
114 OUT PULONG Signature
,
115 OUT PULONG PartitionCount
,
116 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
119 ANSI_STRING TempString
;
121 UNICODE_STRING DeviceName
;
123 PDEVICE_OBJECT DeviceObject
;
124 PFILE_OBJECT FileObject
;
125 DISK_GEOMETRY DiskGeometry
;
126 PDRIVE_LAYOUT_INFORMATION DriveLayout
;
129 IO_STATUS_BLOCK StatusBlock
;
130 LARGE_INTEGER PartitionOffset
;
131 PPARTITION_SECTOR PartitionBuffer
;
134 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
136 /* Convert it to Unicode */
137 RtlInitAnsiString(&TempString
, Buffer
);
138 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
139 if (!NT_SUCCESS(Status
)) return FALSE
;
141 /* Get the device pointer */
142 Status
= IoGetDeviceObjectPointer(&DeviceName
,
146 *DiskDeviceObject
= DeviceObject
;
148 /* Free the string */
149 RtlFreeUnicodeString(&DeviceName
);
151 /* Move on if we failed */
152 if (!NT_SUCCESS(Status
)) return FALSE
;
154 /* Build an IRP to determine the sector size */
155 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
156 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
161 sizeof(DISK_GEOMETRY
),
168 ObDereferenceObject(FileObject
);
172 /* Call the driver and check if we have to wait on it */
173 Status
= IoCallDriver(DeviceObject
, Irp
);
174 if (Status
== STATUS_PENDING
)
176 /* Wait on the driver */
177 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
178 Status
= StatusBlock
.Status
;
181 /* Check if we failed */
182 if (!NT_SUCCESS(Status
))
185 ObDereferenceObject(FileObject
);
189 /* Read the partition table */
190 Status
= IoReadPartitionTable(DeviceObject
,
191 DiskGeometry
.BytesPerSector
,
195 /* Dereference the file object */
196 ObDereferenceObject(FileObject
);
197 if (!NT_SUCCESS(Status
)) return FALSE
;
199 /* Set the offset to 0 */
200 PartitionOffset
.QuadPart
= 0;
202 /* Allocate a buffer for the partition */
203 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
204 DiskGeometry
.BytesPerSector
,
206 if (!PartitionBuffer
) return FALSE
;
208 /* Build an IRP to read the partition sector */
209 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
210 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
213 DiskGeometry
.BytesPerSector
,
218 /* Call the driver and check if we have to wait */
219 Status
= IoCallDriver(DeviceObject
, Irp
);
220 if (Status
== STATUS_PENDING
)
222 /* Wait for completion */
223 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
224 Status
= StatusBlock
.Status
;
227 /* Check if we failed */
228 if (!NT_SUCCESS(Status
))
231 ExFreePool(PartitionBuffer
);
232 ExFreePool(DriveLayout
);
236 /* Calculate the MBR checksum */
238 for (j
= 0; j
< 128; j
++)
240 Checksum
+= ((PULONG
)PartitionBuffer
)[j
];
243 /* Save the signature and checksum */
244 *CheckSum
= ~Checksum
+ 1;
245 *Signature
= DriveLayout
->Signature
;
246 *PartitionCount
= DriveLayout
->PartitionCount
;
248 /* Free the buffer */
249 ExFreePool(PartitionBuffer
);
250 ExFreePool(DriveLayout
);
257 IopAssignArcNamesToCdrom(IN PULONG Buffer
,
261 ANSI_STRING TempString
, ArcNameString
;
262 UNICODE_STRING DeviceName
, ArcName
;
264 LARGE_INTEGER PartitionOffset
;
266 IO_STATUS_BLOCK IoStatusBlock
;
268 ULONG i
, CheckSum
= 0;
269 PDEVICE_OBJECT DeviceObject
;
270 PFILE_OBJECT FileObject
;
272 /* Build the device name */
273 sprintf(ArcBuffer
, "\\Device\\CdRom%lu", DiskNumber
);
275 /* Convert it to Unicode */
276 RtlInitAnsiString(&TempString
, ArcBuffer
);
277 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
278 if (!NT_SUCCESS(Status
)) return FALSE
;
280 /* Get the device for it */
281 Status
= IoGetDeviceObjectPointer(&DeviceName
,
282 FILE_READ_ATTRIBUTES
,
285 if (!NT_SUCCESS(Status
))
287 /* Free the string and fail */
288 RtlFreeUnicodeString(&DeviceName
);
292 /* Setup the event */
293 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
295 /* Set the offset and build the read IRP */
296 PartitionOffset
.QuadPart
= 0x8000;
297 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
306 /* Free the string and fail */
307 RtlFreeUnicodeString(&DeviceName
);
311 /* Call the driver and check if we have to wait on it */
312 Status
= IoCallDriver(DeviceObject
, Irp
);
313 if (Status
== STATUS_PENDING
)
315 /* Wait for completion */
316 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
317 Status
= IoStatusBlock
.Status
;
320 /* Dereference the file object */
321 ObDereferenceObject(FileObject
);
322 if (!NT_SUCCESS(Status
)) return FALSE
;
324 /* Now calculate the checksum */
325 for (i
= 0; i
< 2048 / sizeof(ULONG
); i
++) CheckSum
+= Buffer
[i
];
328 * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
329 * ARC Path name, and what happens here is a comparision of both checksums
330 * in order to see if this is the actual boot CD.
332 * In ReactOS this doesn't currently happen, instead we have a hack on top
333 * of this file which scans the CD for the ntoskrnl.exe file, then modifies
334 * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
335 * get the same state as if NTLDR had properly booted us, except that we do
336 * not actually need to check the signature, since the hack already did the
337 * check for ntoskrnl.exe, which is just as good.
339 * The signature code stays however, because eventually FreeLDR will work
340 * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
342 if (IopApplyRosCdromArcHack(DiskNumber
))
344 /* This is the boot CD-ROM, build the ARC name */
345 sprintf(ArcBuffer
, "\\ArcName\\%s", KeLoaderBlock
->ArcBootDeviceName
);
347 /* Convert it to Unicode */
348 RtlInitAnsiString(&ArcNameString
, ArcBuffer
);
349 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &ArcNameString
, TRUE
);
350 if (!NT_SUCCESS(Status
)) return FALSE
;
352 /* Create the symbolic link and free the strings */
353 IoAssignArcName(&ArcName
, &DeviceName
);
354 RtlFreeUnicodeString(&ArcName
);
355 RtlFreeUnicodeString(&DeviceName
);
357 /* Let caller know that we've found the boot CD */
361 /* No boot CD found */
367 IoCreateArcNames(VOID
)
369 PLOADER_PARAMETER_BLOCK LoaderBlock
= KeLoaderBlock
;
370 PCONFIGURATION_INFORMATION ConfigInfo
= IoGetConfigurationInformation();
371 PARC_DISK_INFORMATION ArcDiskInfo
= LoaderBlock
->ArcDiskInformation
;
372 CHAR ArcBuffer
[256], Buffer
[256];
373 ANSI_STRING ArcBootString
, ArcSystemString
, ArcString
, TempString
, BootString
;
374 UNICODE_STRING ArcName
, BootPath
, DeviceName
;
377 PDEVICE_OBJECT DeviceObject
;
378 ULONG Signature
, Checksum
, PartitionCount
;
379 PLIST_ENTRY NextEntry
;
380 PARC_DISK_SIGNATURE ArcDiskEntry
;
382 BOOLEAN FoundBoot
= FALSE
;
383 PULONG PartitionBuffer
;
385 /* Check if we only have one disk on the machine */
386 SingleDisk
= ArcDiskInfo
->DiskSignatureListHead
.Flink
->Flink
==
387 (&ArcDiskInfo
->DiskSignatureListHead
);
389 /* Create the global HAL partition name */
390 sprintf(ArcBuffer
, "\\ArcName\\%s", LoaderBlock
->ArcHalDeviceName
);
391 RtlInitAnsiString(&ArcString
, ArcBuffer
);
392 RtlAnsiStringToUnicodeString(&IoArcHalDeviceName
, &ArcString
, TRUE
);
394 /* Create the global system partition name */
395 sprintf(ArcBuffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
396 RtlInitAnsiString(&ArcString
, ArcBuffer
);
397 RtlAnsiStringToUnicodeString(&IoArcBootDeviceName
, &ArcString
, TRUE
);
399 /* Allocate memory for the string */
400 Length
= strlen(LoaderBlock
->ArcBootDeviceName
) + sizeof(ANSI_NULL
);
401 IoLoaderArcBootDeviceName
= ExAllocatePoolWithTag(PagedPool
,
404 if (IoLoaderArcBootDeviceName
)
407 RtlMoveMemory(IoLoaderArcBootDeviceName
,
408 LoaderBlock
->ArcBootDeviceName
,
412 /* Check if we only found a disk, but we're booting from CD-ROM */
413 if ((SingleDisk
) && strstr(LoaderBlock
->ArcBootDeviceName
, "cdrom"))
415 /* Then disable single-disk mode, since there's a CD drive out there */
419 /* Build the boot strings */
420 RtlInitAnsiString(&ArcBootString
, LoaderBlock
->ArcBootDeviceName
);
421 RtlInitAnsiString(&ArcSystemString
, LoaderBlock
->ArcHalDeviceName
);
423 /* Loop every detected disk */
424 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
426 /* Get information about the disk */
427 if (!IopGetDiskInformation(i
,
438 for (NextEntry
= ArcDiskInfo
->DiskSignatureListHead
.Flink
;
439 NextEntry
!= &ArcDiskInfo
->DiskSignatureListHead
;
440 NextEntry
= NextEntry
->Flink
)
442 /* Get the current ARC disk signature entry */
443 ArcDiskEntry
= CONTAINING_RECORD(NextEntry
,
448 * Now check if the signature and checksum match, unless this is
449 * the only disk that was in the ARC list, and also in the device
450 * tree, in which case the check is bypassed and we accept the disk
452 if (((SingleDisk
) && (ConfigInfo
->DiskCount
== 1)) ||
453 ((Checksum
== ArcDiskEntry
->CheckSum
) &&
454 (Signature
== ArcDiskEntry
->Signature
)))
456 /* Build the NT Device Name */
457 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
459 /* Convert it to Unicode */
460 RtlInitAnsiString(&TempString
, Buffer
);
461 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
462 if (!NT_SUCCESS(Status
)) continue;
464 /* Build the ARC Device Name */
465 sprintf(ArcBuffer
, "\\ArcName\\%s", ArcDiskEntry
->ArcName
);
467 /* Convert it to Unicode */
468 RtlInitAnsiString(&ArcString
, ArcBuffer
);
469 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &ArcString
, TRUE
);
470 if (!NT_SUCCESS(Status
)) continue;
472 /* Create the symbolic link and free the strings */
473 IoAssignArcName(&ArcName
, &DeviceName
);
474 RtlFreeUnicodeString(&ArcName
);
475 RtlFreeUnicodeString(&DeviceName
);
477 /* Loop all the partitions */
478 for (j
= 0; j
< PartitionCount
; j
++)
480 /* Build the partition device name */
481 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition%lu", i
, j
+ 1);
483 /* Convert it to Unicode */
484 RtlInitAnsiString(&TempString
, Buffer
);
485 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
486 if (!NT_SUCCESS(Status
)) continue;
488 /* Build the partial ARC name for this partition */
489 sprintf(ArcBuffer
, "%spartition(%lu)", ArcDiskEntry
->ArcName
, j
+ 1);
490 RtlInitAnsiString(&ArcString
, ArcBuffer
);
492 /* Check if this is the boot device */
493 if (RtlEqualString(&ArcString
, &ArcBootString
, TRUE
))
495 /* Remember that we found a Hard Disk Boot Device */
499 /* Check if it's the system boot partition */
500 if (RtlEqualString(&ArcString
, &ArcSystemString
, TRUE
))
502 /* It is, create a Unicode string for it */
503 RtlInitAnsiString(&BootString
, LoaderBlock
->NtHalPathName
);
504 Status
= RtlAnsiStringToUnicodeString(&BootPath
, &BootString
, TRUE
);
505 if (NT_SUCCESS(Status
))
507 /* FIXME: Save in registry */
509 /* Free the string now */
510 RtlFreeUnicodeString(&BootPath
);
514 /* Build the full ARC name */
515 sprintf(Buffer
, "\\ArcName\\%spartition(%lu)", ArcDiskEntry
->ArcName
, j
+ 1);
517 /* Convert it to Unicode */
518 RtlInitAnsiString(&ArcString
, Buffer
);
519 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &ArcString
, TRUE
);
520 if (!NT_SUCCESS(Status
)) continue;
522 /* Create the symbolic link and free the strings */
523 IoAssignArcName(&ArcName
, &DeviceName
);
524 RtlFreeUnicodeString(&ArcName
);
525 RtlFreeUnicodeString(&DeviceName
);
531 /* Check if we didn't find the boot disk */
534 /* Allocate a buffer for the CD-ROM MBR */
535 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
, 2048, TAG_IO
);
536 if (!PartitionBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
538 /* Loop every CD-ROM */
539 for (i
= 0; i
< ConfigInfo
->CdRomCount
; i
++)
541 /* Give it an ARC name */
542 if (IopAssignArcNamesToCdrom(PartitionBuffer
, i
)) break;
545 /* Free the buffer */
546 ExFreePool(PartitionBuffer
);
550 return STATUS_SUCCESS
;
555 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
556 OUT PANSI_STRING NtBootPath
)
558 OBJECT_ATTRIBUTES ObjectAttributes
;
560 CHAR Buffer
[256], AnsiBuffer
[256];
561 WCHAR ArcNameBuffer
[64];
562 ANSI_STRING TargetString
, ArcString
, TempString
;
563 UNICODE_STRING LinkName
, TargetName
, ArcName
;
566 /* Create the Unicode name for the current ARC boot device */
567 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
568 RtlInitAnsiString(&TargetString
, Buffer
);
569 Status
= RtlAnsiStringToUnicodeString(&TargetName
, &TargetString
, TRUE
);
570 if (!NT_SUCCESS(Status
)) return FALSE
;
572 /* Initialize the attributes and open the link */
573 InitializeObjectAttributes(&ObjectAttributes
,
575 OBJ_CASE_INSENSITIVE
,
578 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
579 SYMBOLIC_LINK_ALL_ACCESS
,
581 if (!NT_SUCCESS(Status
))
583 /* We failed, free the string */
584 RtlFreeUnicodeString(&TargetName
);
588 /* Query the current \\SystemRoot */
589 ArcName
.Buffer
= ArcNameBuffer
;
591 ArcName
.MaximumLength
= sizeof(ArcNameBuffer
);
592 Status
= NtQuerySymbolicLinkObject(LinkHandle
, &ArcName
, NULL
);
593 if (!NT_SUCCESS(Status
))
595 /* We failed, free the string */
596 RtlFreeUnicodeString(&TargetName
);
600 /* Convert it to Ansi */
601 ArcString
.Buffer
= AnsiBuffer
;
602 ArcString
.Length
= 0;
603 ArcString
.MaximumLength
= sizeof(AnsiBuffer
);
604 Status
= RtlUnicodeStringToAnsiString(&ArcString
, &ArcName
, FALSE
);
605 AnsiBuffer
[ArcString
.Length
] = ANSI_NULL
;
607 /* Close the link handle and free the name */
608 ObCloseHandle(LinkHandle
, KernelMode
);
609 RtlFreeUnicodeString(&TargetName
);
611 /* Setup the system root name again */
612 RtlInitAnsiString(&TempString
, "\\SystemRoot");
613 Status
= RtlAnsiStringToUnicodeString(&LinkName
, &TempString
, TRUE
);
614 if (!NT_SUCCESS(Status
)) return FALSE
;
616 /* Open the symbolic link for it */
617 InitializeObjectAttributes(&ObjectAttributes
,
619 OBJ_CASE_INSENSITIVE
,
622 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
623 SYMBOLIC_LINK_ALL_ACCESS
,
625 if (!NT_SUCCESS(Status
)) return FALSE
;
628 NtMakeTemporaryObject(LinkHandle
);
629 ObCloseHandle(LinkHandle
, KernelMode
);
631 /* Now create the new name for it */
632 sprintf(Buffer
, "%s%s", ArcString
.Buffer
, LoaderBlock
->NtBootPathName
);
634 /* Copy it into the passed parameter and null-terminate it */
635 RtlCopyString(NtBootPath
, &ArcString
);
636 Buffer
[strlen(Buffer
) - 1] = ANSI_NULL
;
638 /* Setup the Unicode-name for the new symbolic link value */
639 RtlInitAnsiString(&TargetString
, Buffer
);
640 InitializeObjectAttributes(&ObjectAttributes
,
642 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
645 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TargetString
, TRUE
);
646 if (!NT_SUCCESS(Status
)) return FALSE
;
649 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
650 SYMBOLIC_LINK_ALL_ACCESS
,
654 /* Free all the strings and close the handle and return success */
655 RtlFreeUnicodeString(&ArcName
);
656 RtlFreeUnicodeString(&LinkName
);
657 ObCloseHandle(LinkHandle
, KernelMode
);