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)
12 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
18 /* FUNCTIONS ****************************************************************/
23 IopApplyRosCdromArcHack(IN ULONG i
)
25 ULONG DeviceNumber
= -1;
26 OBJECT_ATTRIBUTES ObjectAttributes
;
27 UNICODE_STRING DeviceName
;
28 WCHAR Buffer
[MAX_PATH
];
29 CHAR AnsiBuffer
[MAX_PATH
];
30 FILE_BASIC_INFORMATION FileInfo
;
34 /* Only ARC Name left - Build full ARC Name */
35 p
= strstr(KeLoaderBlock
->ArcBootDeviceName
, "cdrom");
38 /* Try to find the installer */
39 swprintf(Buffer
, L
"\\Device\\CdRom%lu\\reactos\\ntoskrnl.exe", i
);
40 RtlInitUnicodeString(&DeviceName
, Buffer
);
41 InitializeObjectAttributes(&ObjectAttributes
,
46 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
47 if (NT_SUCCESS(Status
)) DeviceNumber
= i
;
49 /* Try to find live CD boot */
51 L
"\\Device\\CdRom%lu\\reactos\\system32\\ntoskrnl.exe",
53 RtlInitUnicodeString(&DeviceName
, Buffer
);
54 InitializeObjectAttributes(&ObjectAttributes
,
59 Status
= ZwQueryAttributesFile(&ObjectAttributes
, &FileInfo
);
60 if (NT_SUCCESS(Status
)) DeviceNumber
= i
;
63 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
65 /* Adjust original command line */
70 strcpy(AnsiBuffer
, q
);
71 sprintf(p
, "cdrom(%lu)", DeviceNumber
);
72 strcat(p
, AnsiBuffer
);
76 /* Return whether this is the CD or not */
77 if (DeviceNumber
!= 1) return TRUE
;
84 IopEnumerateDisks(IN PLIST_ENTRY ListHead
)
87 ANSI_STRING TempString
;
89 UNICODE_STRING DeviceName
;
91 PDEVICE_OBJECT DeviceObject
;
92 PFILE_OBJECT FileObject
;
93 DISK_GEOMETRY DiskGeometry
;
94 PDRIVE_LAYOUT_INFORMATION DriveLayout
;
97 IO_STATUS_BLOCK StatusBlock
;
98 LARGE_INTEGER PartitionOffset
;
99 PPARTITION_SECTOR PartitionBuffer
;
100 PDISKENTRY DiskEntry
;
102 /* Loop every detected disk */
103 for (i
= 0; i
< IoGetConfigurationInformation()->DiskCount
; i
++)
106 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", i
);
108 /* Convert it to Unicode */
109 RtlInitAnsiString(&TempString
, Buffer
);
110 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
111 if (!NT_SUCCESS(Status
)) continue;
113 /* Get the device pointer */
114 Status
= IoGetDeviceObjectPointer(&DeviceName
,
119 /* Free the string */
120 RtlFreeUnicodeString(&DeviceName
);
122 /* Move on if we failed */
123 if (!NT_SUCCESS(Status
)) continue;
125 /* Allocate the ROS disk Entry */
126 DiskEntry
= ExAllocatePoolWithTag(PagedPool
, sizeof(DISKENTRY
), TAG_IO
);
127 DiskEntry
->DiskNumber
= i
;
128 DiskEntry
->DeviceObject
= DeviceObject
;
130 /* Build an IRP to determine the sector size */
131 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
132 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
137 sizeof(DISK_GEOMETRY
),
144 ObDereferenceObject(FileObject
);
148 /* Call the driver and check if we have to wait on it */
149 Status
= IoCallDriver(DeviceObject
, Irp
);
150 if (Status
== STATUS_PENDING
)
152 /* Wait on the driver */
153 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
154 Status
= StatusBlock
.Status
;
157 /* Check if we failed */
158 if (!NT_SUCCESS(Status
))
161 ObDereferenceObject(FileObject
);
165 /* Read the partition table */
166 Status
= IoReadPartitionTable(DeviceObject
,
167 DiskGeometry
.BytesPerSector
,
171 /* Dereference the file object */
172 ObDereferenceObject(FileObject
);
173 if (!NT_SUCCESS(Status
)) continue;
175 /* Set the offset to 0 */
176 PartitionOffset
.QuadPart
= 0;
178 /* Allocate a buffer for the partition */
179 PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
180 DiskGeometry
.BytesPerSector
,
182 if (!PartitionBuffer
) continue;
184 /* Build an IRP to read the partition sector */
185 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
186 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
189 DiskGeometry
.BytesPerSector
,
194 /* Call the driver and check if we have to wait */
195 Status
= IoCallDriver(DeviceObject
, Irp
);
196 if (Status
== STATUS_PENDING
)
198 /* Wait for completion */
199 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
200 Status
= StatusBlock
.Status
;
203 /* Check if we failed */
204 if (!NT_SUCCESS(Status
))
207 ExFreePool(PartitionBuffer
);
208 ExFreePool(DriveLayout
);
212 /* Calculate the MBR checksum */
213 DiskEntry
->Checksum
= 0;
214 for (j
= 0; j
< 128; j
++)
216 DiskEntry
->Checksum
+= ((PULONG
)PartitionBuffer
)[j
];
219 /* Save the signature and checksum */
220 DiskEntry
->Checksum
= ~DiskEntry
->Checksum
+ 1;
221 DiskEntry
->Signature
= DriveLayout
->Signature
;
222 DiskEntry
->PartitionCount
= DriveLayout
->PartitionCount
;
224 /* Insert it into the list */
225 InsertTailList(ListHead
, &DiskEntry
->ListEntry
);
227 /* Free the buffer */
228 ExFreePool(PartitionBuffer
);
229 ExFreePool(DriveLayout
);
236 IopAssignArcNamesToDisk(IN PDEVICE_OBJECT DeviceObject
,
237 IN PCHAR BootArcName
,
239 IN ULONG PartitionCount
,
240 IN PBOOLEAN FoundHdBoot
)
244 ANSI_STRING TempString
, ArcNameString
, BootString
;
245 ANSI_STRING ArcBootString
, ArcSystemString
;
246 UNICODE_STRING DeviceName
, ArcName
, BootPath
;
251 *FoundHdBoot
= FALSE
;
253 /* Build the boot strings */
254 RtlInitAnsiString(&ArcBootString
, KeLoaderBlock
->ArcBootDeviceName
);
255 RtlInitAnsiString(&ArcSystemString
, KeLoaderBlock
->ArcHalDeviceName
);
257 /* Build the NT Device Name */
258 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition0", DiskNumber
);
260 /* Convert it to unicode */
261 RtlInitAnsiString(&TempString
, Buffer
);
262 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
263 if (!NT_SUCCESS(Status
)) return Status
;
265 /* Build the ARC Device Name */
266 sprintf(ArcBuffer
, "\\ArcName\\%s", BootArcName
);
268 /* Convert it to Unicode */
269 RtlInitAnsiString(&ArcNameString
, ArcBuffer
);
270 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &ArcNameString
, TRUE
);
271 if (!NT_SUCCESS(Status
)) return Status
;
273 /* Create the symbolic link and free the strings */
274 IoAssignArcName(&ArcName
, &DeviceName
);
275 RtlFreeUnicodeString(&ArcName
);
276 RtlFreeUnicodeString(&DeviceName
);
278 /* Loop all the partitions */
279 for (i
= 0; i
< PartitionCount
; i
++)
281 /* Build the partition device name */
282 sprintf(Buffer
, "\\Device\\Harddisk%lu\\Partition%lu", DiskNumber
, i
+1);
284 /* Convert it to Unicode */
285 RtlInitAnsiString(&TempString
, Buffer
);
286 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
287 if (!NT_SUCCESS(Status
)) continue;
289 /* Build the partial ARC name for this partition */
290 sprintf(ArcBuffer
, "%spartition(%lu)", BootArcName
, i
+ 1);
291 RtlInitAnsiString(&ArcNameString
, ArcBuffer
);
293 /* Check if this is the boot device */
294 if (RtlEqualString(&ArcNameString
, &ArcBootString
, TRUE
))
296 /* Remember that we found a Hard Disk Boot Device */
300 /* Check if it's the system boot partition */
301 if (RtlEqualString(&ArcNameString
, &ArcSystemString
, TRUE
))
303 /* It is, create a Unicode string for it */
304 RtlInitAnsiString(&BootString
, KeLoaderBlock
->NtHalPathName
);
305 Status
= RtlAnsiStringToUnicodeString(&BootPath
, &BootString
, TRUE
);
306 if (NT_SUCCESS(Status
))
308 /* FIXME: Save in registry */
310 /* Free the string now */
311 RtlFreeUnicodeString(&BootPath
);
315 /* Build the full ARC name */
316 sprintf(Buffer
, "\\ArcName\\%spartition(%lu)", BootArcName
, i
+ 1);
318 /* Convert it to Unicode */
319 RtlInitAnsiString(&ArcNameString
, Buffer
);
320 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &ArcNameString
, TRUE
);
321 if (!NT_SUCCESS(Status
)) continue;
323 /* Create the symbolic link and free the strings */
324 IoAssignArcName(&ArcName
, &DeviceName
);
325 RtlFreeUnicodeString(&ArcName
);
326 RtlFreeUnicodeString(&DeviceName
);
330 return STATUS_SUCCESS
;
336 IopAssignArcNamesToCdrom(IN PULONG Buffer
,
340 ANSI_STRING TempString
, ArcNameString
;
341 UNICODE_STRING DeviceName
, ArcName
;
343 LARGE_INTEGER PartitionOffset
;
345 IO_STATUS_BLOCK IoStatusBlock
;
347 ULONG i
, CheckSum
= 0;
348 PDEVICE_OBJECT DeviceObject
;
349 PFILE_OBJECT FileObject
;
351 /* Build the device name */
352 sprintf(ArcBuffer
, "\\Device\\CdRom%lu", DiskNumber
);
354 /* Convert it to Unicode */
355 RtlInitAnsiString(&TempString
, ArcBuffer
);
356 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &TempString
, TRUE
);
357 if (!NT_SUCCESS(Status
)) return FALSE
;
359 /* Get the device for it */
360 Status
= IoGetDeviceObjectPointer(&DeviceName
,
361 FILE_READ_ATTRIBUTES
,
364 if (!NT_SUCCESS(Status
))
366 /* Free the string and fail */
367 RtlFreeUnicodeString(&DeviceName
);
371 /* Setup the event */
372 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
374 /* Set the offset and build the read IRP */
375 PartitionOffset
.QuadPart
= 0x8000;
376 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
385 /* Free the string and fail */
386 RtlFreeUnicodeString(&DeviceName
);
390 /* Call the driver and check if we have to wait on it */
391 Status
= IoCallDriver(DeviceObject
, Irp
);
392 if (Status
== STATUS_PENDING
)
394 /* Wait for completion */
395 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
396 Status
= IoStatusBlock
.Status
;
399 /* Dereference the file object */
400 ObDereferenceObject(FileObject
);
401 if (!NT_SUCCESS(Status
)) return FALSE
;
403 /* Now calculate the checksum */
404 for (i
= 0; i
< 2048 / sizeof(ULONG
); i
++) CheckSum
+= Buffer
[i
];
407 * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
408 * ARC Path name, and what happens here is a comparision of both checksums
409 * in order to see if this is the actual boot CD.
411 * In ReactOS this doesn't currently happen, instead we have a hack on top
412 * of this file which scans the CD for the ntoskrnl.exe file, then modifies
413 * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
414 * get the same state as if NTLDR had properly booted us, except that we do
415 * not actually need to check the signature, since the hack already did the
416 * check for ntoskrnl.exe, which is just as good.
418 * The signature code stays however, because eventually FreeLDR will work
419 * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
421 if (IopApplyRosCdromArcHack(DiskNumber
))
423 /* This is the boot CD-ROM, build the ARC name */
424 sprintf(ArcBuffer
, "\\ArcName\\%s", KeLoaderBlock
->ArcBootDeviceName
);
426 /* Convert it to Unicode */
427 RtlInitAnsiString(&ArcNameString
, ArcBuffer
);
428 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &ArcNameString
, TRUE
);
429 if (!NT_SUCCESS(Status
)) return FALSE
;
431 /* Create the symbolic link and free the strings */
432 IoAssignArcName(&ArcName
, &DeviceName
);
433 RtlFreeUnicodeString(&ArcName
);
434 RtlFreeUnicodeString(&DeviceName
);
436 /* Let caller know that we've found the boot CD */
440 /* No boot CD found */
444 NTSTATUS INIT_FUNCTION
445 IoCreateArcNames(VOID
)
447 PCONFIGURATION_INFORMATION ConfigInfo
;
450 PLIST_ENTRY BiosDiskListHead
, Entry
;
451 LIST_ENTRY DiskListHead
;
452 PARC_DISK_SIGNATURE ArcDiskEntry
;
453 PDISKENTRY DiskEntry
;
454 BOOLEAN FoundBoot
= FALSE
;
457 ConfigInfo
= IoGetConfigurationInformation();
459 /* Get the boot ARC disk list */
460 BiosDiskListHead
= &KeLoaderBlock
->ArcDiskInformation
->
461 DiskSignatureListHead
;
463 /* Enumerate system disks */
464 InitializeListHead(&DiskListHead
);
465 IopEnumerateDisks(&DiskListHead
);
467 while (!IsListEmpty(BiosDiskListHead
))
469 Entry
= RemoveHeadList(BiosDiskListHead
);
470 ArcDiskEntry
= CONTAINING_RECORD(Entry
, ARC_DISK_SIGNATURE
, ListEntry
);
471 Entry
= DiskListHead
.Flink
;
472 while (Entry
!= &DiskListHead
)
474 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
475 DPRINT1("Entry: %s\n", ArcDiskEntry
->ArcName
);
476 if (DiskEntry
->Checksum
== ArcDiskEntry
->CheckSum
&&
477 DiskEntry
->Signature
== ArcDiskEntry
->Signature
)
479 Status
= IopAssignArcNamesToDisk(DiskEntry
->DeviceObject
,
480 ArcDiskEntry
->ArcName
,
481 DiskEntry
->DiskNumber
,
482 DiskEntry
->PartitionCount
,
485 RemoveEntryList(&DiskEntry
->ListEntry
);
486 ExFreePool(DiskEntry
);
489 Entry
= Entry
->Flink
;
493 while (!IsListEmpty(&DiskListHead
))
495 Entry
= RemoveHeadList(&DiskListHead
);
496 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
497 ExFreePool(DiskEntry
);
500 /* Check if we didn't find the boot disk */
503 /* Allocate a buffer for the CD-ROM MBR */
504 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, 2048, TAG_IO
);
505 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
507 /* Loop every CD-ROM */
508 for (i
= 0; i
< ConfigInfo
->CdRomCount
; i
++)
510 /* Give it an ARC name */
511 if (IopAssignArcNamesToCdrom(Buffer
, i
)) break;
514 /* Free the buffer */
519 return STATUS_SUCCESS
;
524 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
525 OUT PANSI_STRING NtBootPath
)
527 OBJECT_ATTRIBUTES ObjectAttributes
;
529 CHAR Buffer
[256], AnsiBuffer
[256];
530 WCHAR ArcNameBuffer
[64];
531 ANSI_STRING TargetString
, ArcString
, TempString
;
532 UNICODE_STRING LinkName
, TargetName
, ArcName
;
535 /* Create the Unicode name for the current ARC boot device */
536 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
537 RtlInitAnsiString(&TargetString
, Buffer
);
538 Status
= RtlAnsiStringToUnicodeString(&TargetName
, &TargetString
, TRUE
);
539 if (!NT_SUCCESS(Status
)) return FALSE
;
541 /* Initialize the attributes and open the link */
542 InitializeObjectAttributes(&ObjectAttributes
,
544 OBJ_CASE_INSENSITIVE
,
547 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
548 SYMBOLIC_LINK_ALL_ACCESS
,
550 if (!NT_SUCCESS(Status
))
552 /* We failed, free the string */
553 RtlFreeUnicodeString(&TargetName
);
557 /* Query the current \\SystemRoot */
558 ArcName
.Buffer
= ArcNameBuffer
;
560 ArcName
.MaximumLength
= sizeof(ArcNameBuffer
);
561 Status
= NtQuerySymbolicLinkObject(LinkHandle
, &ArcName
, NULL
);
562 if (!NT_SUCCESS(Status
))
564 /* We failed, free the string */
565 RtlFreeUnicodeString(&TargetName
);
569 /* Convert it to Ansi */
570 ArcString
.Buffer
= AnsiBuffer
;
571 ArcString
.Length
= 0;
572 ArcString
.MaximumLength
= sizeof(AnsiBuffer
);
573 Status
= RtlUnicodeStringToAnsiString(&ArcString
, &ArcName
, FALSE
);
574 AnsiBuffer
[ArcString
.Length
] = ANSI_NULL
;
576 /* Close the link handle and free the name */
577 ObCloseHandle(LinkHandle
, KernelMode
);
578 RtlFreeUnicodeString(&TargetName
);
580 /* Setup the system root name again */
581 RtlInitAnsiString(&TempString
, "\\SystemRoot");
582 Status
= RtlAnsiStringToUnicodeString(&LinkName
, &TempString
, TRUE
);
583 if (!NT_SUCCESS(Status
)) return FALSE
;
585 /* Open the symbolic link for it */
586 InitializeObjectAttributes(&ObjectAttributes
,
588 OBJ_CASE_INSENSITIVE
,
591 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
592 SYMBOLIC_LINK_ALL_ACCESS
,
594 if (!NT_SUCCESS(Status
)) return FALSE
;
597 NtMakeTemporaryObject(LinkHandle
);
598 ObCloseHandle(LinkHandle
, KernelMode
);
600 /* Now create the new name for it */
601 sprintf(Buffer
, "%s%s", ArcString
.Buffer
, LoaderBlock
->NtBootPathName
);
603 /* Copy it into the passed parameter and null-terminate it */
604 RtlCopyString(NtBootPath
, &ArcString
);
605 Buffer
[strlen(Buffer
) - 1] = ANSI_NULL
;
607 /* Setup the Unicode-name for the new symbolic link value */
608 RtlInitAnsiString(&TargetString
, Buffer
);
609 InitializeObjectAttributes(&ObjectAttributes
,
611 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
614 Status
= RtlAnsiStringToUnicodeString(&ArcName
, &TargetString
, TRUE
);
615 if (!NT_SUCCESS(Status
)) return FALSE
;
618 Status
= NtCreateSymbolicLinkObject(&LinkHandle
,
619 SYMBOLIC_LINK_ALL_ACCESS
,
623 /* Free all the strings and close the handle and return success */
624 RtlFreeUnicodeString(&ArcName
);
625 RtlFreeUnicodeString(&LinkName
);
626 ObCloseHandle(LinkHandle
, KernelMode
);