- Part 2 of ARC boot changes: Major modifications done to the existing code, as well...
[reactos.git] / reactos / ntoskrnl / io / iomgr / arcname.c
1 /* $Id$
2 *
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
7 *
8 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
9 */
10
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* MACROS *******************************************************************/
19
20 #define FS_VOLUME_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_VOLUME_INFORMATION))
21
22 /* FUNCTIONS ****************************************************************/
23
24 static
25 NTSTATUS
26 STDCALL
27 INIT_FUNCTION
28 DiskQueryRoutine(PWSTR ValueName,
29 ULONG ValueType,
30 PVOID ValueData,
31 ULONG ValueLength,
32 PVOID Context,
33 PVOID EntryContext)
34 {
35 PLIST_ENTRY ListHead = (PLIST_ENTRY)Context;
36 PULONG GlobalDiskCount = (PULONG)EntryContext;
37 PDISKENTRY DiskEntry;
38 UNICODE_STRING NameU;
39
40 if (ValueType == REG_SZ &&
41 ValueLength == 20 * sizeof(WCHAR))
42 {
43 DiskEntry = ExAllocatePool(PagedPool, sizeof(DISKENTRY));
44 if (DiskEntry == NULL)
45 {
46 return STATUS_NO_MEMORY;
47 }
48 DiskEntry->DiskNumber = (*GlobalDiskCount)++;
49
50 NameU.Buffer = (PWCHAR)ValueData;
51 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
52 RtlUnicodeStringToInteger(&NameU, 16, &DiskEntry->Checksum);
53
54 NameU.Buffer = (PWCHAR)ValueData + 9;
55 RtlUnicodeStringToInteger(&NameU, 16, &DiskEntry->Signature);
56
57 InsertTailList(ListHead, &DiskEntry->ListEntry);
58 }
59
60 return STATUS_SUCCESS;
61 }
62
63 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
64
65 static VOID INIT_FUNCTION
66 IopEnumerateBiosDisks(PLIST_ENTRY ListHead)
67 {
68 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
69 WCHAR Name[255];
70 ULONG AdapterCount;
71 ULONG ControllerCount;
72 ULONG DiskCount;
73 NTSTATUS Status;
74 ULONG GlobalDiskCount=0;
75
76
77 memset(QueryTable, 0, sizeof(QueryTable));
78 QueryTable[0].Name = L"Identifier";
79 QueryTable[0].QueryRoutine = DiskQueryRoutine;
80 QueryTable[0].EntryContext = (PVOID)&GlobalDiskCount;
81
82 AdapterCount = 0;
83 while (1)
84 {
85 swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
86 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
87 Name,
88 &QueryTable[1],
89 NULL,
90 NULL);
91 if (!NT_SUCCESS(Status))
92 {
93 break;
94 }
95
96 swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
97 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
98 Name,
99 &QueryTable[1],
100 NULL,
101 NULL);
102 if (NT_SUCCESS(Status))
103 {
104 ControllerCount = 0;
105 while (1)
106 {
107 swprintf(Name, L"%s\\%lu\\DiskController\\%lu", ROOT_NAME, AdapterCount, ControllerCount);
108 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
109 Name,
110 &QueryTable[1],
111 NULL,
112 NULL);
113 if (!NT_SUCCESS(Status))
114 {
115 break;
116 }
117
118 swprintf(Name, L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral", ROOT_NAME, AdapterCount, ControllerCount);
119 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
120 Name,
121 &QueryTable[1],
122 NULL,
123 NULL);
124 if (NT_SUCCESS(Status))
125 {
126 DiskCount = 0;
127 while (1)
128 {
129 swprintf(Name, L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, ControllerCount, DiskCount);
130 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
131 Name,
132 QueryTable,
133 (PVOID)ListHead,
134 NULL);
135 if (!NT_SUCCESS(Status))
136 {
137 break;
138 }
139 DiskCount++;
140 }
141 }
142 ControllerCount++;
143 }
144 }
145 AdapterCount++;
146 }
147 }
148
149 BOOLEAN
150 INIT_FUNCTION
151 NTAPI
152 IopApplyRosCdromArcHack(IN ULONG i)
153 {
154 ULONG DeviceNumber = -1;
155 OBJECT_ATTRIBUTES ObjectAttributes;
156 UNICODE_STRING DeviceName;
157 WCHAR Buffer[MAX_PATH];
158 CHAR AnsiBuffer[MAX_PATH];
159 FILE_BASIC_INFORMATION FileInfo;
160 NTSTATUS Status;
161 PCHAR p, q;
162
163 /* Only ARC Name left - Build full ARC Name */
164 p = strstr(KeLoaderBlock->ArcBootDeviceName, "cdrom");
165 if (p)
166 {
167 /* Try to find the installer */
168 swprintf(Buffer, L"\\Device\\CdRom%lu\\reactos\\ntoskrnl.exe", i);
169 RtlInitUnicodeString(&DeviceName, Buffer);
170 InitializeObjectAttributes(&ObjectAttributes,
171 &DeviceName,
172 0,
173 NULL,
174 NULL);
175 Status = ZwQueryAttributesFile(&ObjectAttributes, &FileInfo);
176 if (NT_SUCCESS(Status)) DeviceNumber = i;
177
178 /* Try to find live CD boot */
179 swprintf(Buffer,
180 L"\\Device\\CdRom%lu\\reactos\\system32\\ntoskrnl.exe",
181 i);
182 RtlInitUnicodeString(&DeviceName, Buffer);
183 InitializeObjectAttributes(&ObjectAttributes,
184 &DeviceName,
185 0,
186 NULL,
187 NULL);
188 Status = ZwQueryAttributesFile(&ObjectAttributes, &FileInfo);
189 if (NT_SUCCESS(Status)) DeviceNumber = i;
190
191 /* Build the name */
192 sprintf(p, "cdrom(%lu)", DeviceNumber);
193
194 /* Adjust original command line */
195 q = strchr(p, ')');
196 if (q)
197 {
198 q++;
199 strcpy(AnsiBuffer, q);
200 sprintf(p, "cdrom(%lu)", DeviceNumber);
201 strcat(p, AnsiBuffer);
202 }
203 }
204
205 /* Return whether this is the CD or not */
206 if (DeviceNumber != 1) return TRUE;
207 return FALSE;
208 }
209
210 VOID
211 INIT_FUNCTION
212 NTAPI
213 IopEnumerateDisks(IN PLIST_ENTRY ListHead)
214 {
215 ULONG i, j;
216 ANSI_STRING TempString;
217 CHAR Buffer[256];
218 UNICODE_STRING DeviceName;
219 NTSTATUS Status;
220 PDEVICE_OBJECT DeviceObject;
221 PFILE_OBJECT FileObject;
222 DISK_GEOMETRY DiskGeometry;
223 PDRIVE_LAYOUT_INFORMATION DriveLayout;
224 KEVENT Event;
225 PIRP Irp;
226 IO_STATUS_BLOCK StatusBlock;
227 LARGE_INTEGER PartitionOffset;
228 PPARTITION_SECTOR PartitionBuffer;
229 PDISKENTRY DiskEntry;
230
231 /* Loop every detected disk */
232 for (i = 0; i < IoGetConfigurationInformation()->DiskCount; i++)
233 {
234 /* Build the name */
235 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", i);
236
237 /* Convert it to Unicode */
238 RtlInitAnsiString(&TempString, Buffer);
239 Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
240 if (!NT_SUCCESS(Status)) continue;
241
242 /* Get the device pointer */
243 Status = IoGetDeviceObjectPointer(&DeviceName,
244 FILE_READ_DATA,
245 &FileObject,
246 &DeviceObject);
247
248 /* Free the string */
249 RtlFreeUnicodeString(&DeviceName);
250
251 /* Move on if we failed */
252 if (!NT_SUCCESS(Status)) continue;
253
254 /* Allocate the ROS disk Entry */
255 DiskEntry = ExAllocatePoolWithTag(PagedPool, sizeof(DISKENTRY), TAG_IO);
256 DiskEntry->DiskNumber = i;
257 DiskEntry->DeviceObject = DeviceObject;
258
259 /* Build an IRP to determine the sector size */
260 KeInitializeEvent(&Event, NotificationEvent, FALSE);
261 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
262 DeviceObject,
263 NULL,
264 0,
265 &DiskGeometry,
266 sizeof(DISK_GEOMETRY),
267 FALSE,
268 &Event,
269 &StatusBlock);
270 if (!Irp)
271 {
272 /* Try again */
273 ObDereferenceObject(FileObject);
274 continue;
275 }
276
277 /* Call the driver and check if we have to wait on it */
278 Status = IoCallDriver(DeviceObject, Irp);
279 if (Status == STATUS_PENDING)
280 {
281 /* Wait on the driver */
282 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
283 Status = StatusBlock.Status;
284 }
285
286 /* Check if we failed */
287 if (!NT_SUCCESS(Status))
288 {
289 /* Try again */
290 ObDereferenceObject(FileObject);
291 continue;
292 }
293
294 /* Read the partition table */
295 Status = IoReadPartitionTable(DeviceObject,
296 DiskGeometry.BytesPerSector,
297 TRUE,
298 &DriveLayout);
299
300 /* Dereference the file object */
301 ObDereferenceObject(FileObject);
302 if (!NT_SUCCESS(Status)) continue;
303
304 /* Set the offset to 0 */
305 PartitionOffset.QuadPart = 0;
306
307 /* Allocate a buffer for the partition */
308 PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
309 DiskGeometry.BytesPerSector,
310 TAG_IO);
311 if (!PartitionBuffer) continue;
312
313 /* Build an IRP to read the partition sector */
314 KeInitializeEvent(&Event, NotificationEvent, FALSE);
315 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
316 DeviceObject,
317 PartitionBuffer,
318 DiskGeometry.BytesPerSector,
319 &PartitionOffset,
320 &Event,
321 &StatusBlock);
322
323 /* Call the driver and check if we have to wait */
324 Status = IoCallDriver(DeviceObject, Irp);
325 if (Status == STATUS_PENDING)
326 {
327 /* Wait for completion */
328 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
329 Status = StatusBlock.Status;
330 }
331
332 /* Check if we failed */
333 if (!NT_SUCCESS(Status))
334 {
335 /* Try again */
336 ExFreePool(PartitionBuffer);
337 ExFreePool(DriveLayout);
338 continue;
339 }
340
341 /* Calculate the MBR checksum */
342 DiskEntry->Checksum = 0;
343 for (j = 0; j < 128; j++)
344 {
345 DiskEntry->Checksum += ((PULONG)PartitionBuffer)[j];
346 }
347
348 /* Save the signature and checksum */
349 DiskEntry->Checksum = ~DiskEntry->Checksum + 1;
350 DiskEntry->Signature = DriveLayout->Signature;
351 DiskEntry->PartitionCount = DriveLayout->PartitionCount;
352
353 /* Insert it into the list */
354 InsertTailList(ListHead, &DiskEntry->ListEntry);
355
356 /* Free the buffer */
357 ExFreePool(PartitionBuffer);
358 ExFreePool(DriveLayout);
359 }
360 }
361
362 NTSTATUS
363 INIT_FUNCTION
364 NTAPI
365 IopAssignArcNamesToDisk(IN PDEVICE_OBJECT DeviceObject,
366 IN ULONG RDisk,
367 IN ULONG DiskNumber,
368 IN ULONG PartitionCount,
369 IN PBOOLEAN FoundHdBoot)
370 {
371 CHAR Buffer[256];
372 CHAR ArcBuffer[256];
373 ANSI_STRING TempString, ArcNameString, BootString;
374 ANSI_STRING ArcBootString, ArcSystemString;
375 UNICODE_STRING DeviceName, ArcName, BootPath;
376 ULONG i;
377 NTSTATUS Status;
378
379 /* HACK: Build the ARC name that FreeLDR should've given us */
380 CHAR BootArcName[256]; // should come from FREELDR
381 sprintf(BootArcName, "multi(0)disk(0)rdisk(%lu)", RDisk);
382
383 /* Set default */
384 *FoundHdBoot = FALSE;
385
386 /* Build the boot strings */
387 RtlInitAnsiString(&ArcBootString, KeLoaderBlock->ArcBootDeviceName);
388 RtlInitAnsiString(&ArcSystemString, KeLoaderBlock->ArcHalDeviceName);
389
390 /* Build the NT Device Name */
391 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber);
392
393 /* Convert it to unicode */
394 RtlInitAnsiString(&TempString, Buffer);
395 Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
396 if (!NT_SUCCESS(Status)) return Status;
397
398 /* Build the ARC Device Name */
399 sprintf(ArcBuffer, "\\ArcName\\%s", BootArcName);
400
401 /* Convert it to Unicode */
402 RtlInitAnsiString(&ArcNameString, ArcBuffer);
403 Status = RtlAnsiStringToUnicodeString(&ArcName, &ArcNameString, TRUE);
404 if (!NT_SUCCESS(Status)) return Status;
405
406 /* Create the symbolic link and free the strings */
407 IoAssignArcName(&ArcName, &DeviceName);
408 RtlFreeUnicodeString(&ArcName);
409 RtlFreeUnicodeString(&DeviceName);
410
411 /* Loop all the partitions */
412 for (i = 0; i < PartitionCount; i++)
413 {
414 /* Build the partition device name */
415 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", DiskNumber, i+1);
416
417 /* Convert it to Unicode */
418 RtlInitAnsiString(&TempString, Buffer);
419 Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
420 if (!NT_SUCCESS(Status)) continue;
421
422 /* Build the partial ARC name for this partition */
423 sprintf(ArcBuffer, "%spartition(%lu)", BootArcName, i + 1);
424 RtlInitAnsiString(&ArcNameString, ArcBuffer);
425
426 /* Check if this is the boot device */
427 if (RtlEqualString(&ArcNameString, &ArcBootString, TRUE))
428 {
429 /* Remember that we found a Hard Disk Boot Device */
430 *FoundHdBoot = TRUE;
431 }
432
433 /* Check if it's the system boot partition */
434 if (RtlEqualString(&ArcNameString, &ArcSystemString, TRUE))
435 {
436 /* It is, create a Unicode string for it */
437 RtlInitAnsiString(&BootString, KeLoaderBlock->NtHalPathName);
438 Status = RtlAnsiStringToUnicodeString(&BootPath, &BootString, TRUE);
439 if (NT_SUCCESS(Status))
440 {
441 /* FIXME: Save in registry */
442
443 /* Free the string now */
444 RtlFreeUnicodeString(&BootPath);
445 }
446 }
447
448 /* Build the full ARC name */
449 sprintf(Buffer, "\\ArcName\\%spartition(%lu)", BootArcName, i + 1);
450
451 /* Convert it to Unicode */
452 RtlInitAnsiString(&ArcNameString, Buffer);
453 Status = RtlAnsiStringToUnicodeString(&ArcName, &ArcNameString, TRUE);
454 if (!NT_SUCCESS(Status)) continue;
455
456 /* Create the symbolic link and free the strings */
457 IoAssignArcName(&ArcName, &DeviceName);
458 RtlFreeUnicodeString(&ArcName);
459 RtlFreeUnicodeString(&DeviceName);
460 }
461
462 /* Return success */
463 return STATUS_SUCCESS;
464 }
465
466 BOOLEAN
467 INIT_FUNCTION
468 NTAPI
469 IopAssignArcNamesToCdrom(IN PULONG Buffer,
470 IN ULONG DiskNumber)
471 {
472 CHAR ArcBuffer[256];
473 ANSI_STRING TempString, ArcNameString;
474 UNICODE_STRING DeviceName, ArcName;
475 NTSTATUS Status;
476 LARGE_INTEGER PartitionOffset;
477 KEVENT Event;
478 IO_STATUS_BLOCK IoStatusBlock;
479 PIRP Irp;
480 ULONG i, CheckSum = 0;
481 PDEVICE_OBJECT DeviceObject;
482 PFILE_OBJECT FileObject;
483
484 /* Build the device name */
485 sprintf(ArcBuffer, "\\Device\\CdRom%lu", DiskNumber);
486
487 /* Convert it to Unicode */
488 RtlInitAnsiString(&TempString, ArcBuffer);
489 Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
490 if (!NT_SUCCESS(Status)) return FALSE;
491
492 /* Get the device for it */
493 Status = IoGetDeviceObjectPointer(&DeviceName,
494 FILE_READ_ATTRIBUTES,
495 &FileObject,
496 &DeviceObject);
497 if (!NT_SUCCESS(Status))
498 {
499 /* Free the string and fail */
500 RtlFreeUnicodeString(&DeviceName);
501 return FALSE;
502 }
503
504 /* Setup the event */
505 KeInitializeEvent(&Event, NotificationEvent, FALSE);
506
507 /* Set the offset and build the read IRP */
508 PartitionOffset.QuadPart = 0x8000;
509 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
510 DeviceObject,
511 Buffer,
512 2048,
513 &PartitionOffset,
514 &Event,
515 &IoStatusBlock);
516 if (!Irp)
517 {
518 /* Free the string and fail */
519 RtlFreeUnicodeString(&DeviceName);
520 return FALSE;
521 }
522
523 /* Call the driver and check if we have to wait on it */
524 Status = IoCallDriver(DeviceObject, Irp);
525 if (Status == STATUS_PENDING)
526 {
527 /* Wait for completion */
528 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
529 Status = IoStatusBlock.Status;
530 }
531
532 /* Dereference the file object */
533 ObDereferenceObject(FileObject);
534 if (!NT_SUCCESS(Status)) return FALSE;
535
536 /* Now calculate the checksum */
537 for (i = 0; i < 2048 / sizeof(ULONG); i++) CheckSum += Buffer[i];
538
539 /*
540 * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
541 * ARC Path name, and what happens here is a comparision of both checksums
542 * in order to see if this is the actual boot CD.
543 *
544 * In ReactOS this doesn't currently happen, instead we have a hack on top
545 * of this file which scans the CD for the ntoskrnl.exe file, then modifies
546 * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
547 * get the same state as if NTLDR had properly booted us, except that we do
548 * not actually need to check the signature, since the hack already did the
549 * check for ntoskrnl.exe, which is just as good.
550 *
551 * The signature code stays however, because eventually FreeLDR will work
552 * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
553 */
554 if (IopApplyRosCdromArcHack(DiskNumber))
555 {
556 /* This is the boot CD-ROM, build the ARC name */
557 sprintf(ArcBuffer, "\\ArcName\\%s", KeLoaderBlock->ArcBootDeviceName);
558
559 /* Convert it to Unicode */
560 RtlInitAnsiString(&ArcNameString, ArcBuffer);
561 Status = RtlAnsiStringToUnicodeString(&ArcName, &ArcNameString, TRUE);
562 if (!NT_SUCCESS(Status)) return FALSE;
563
564 /* Create the symbolic link and free the strings */
565 IoAssignArcName(&ArcName, &DeviceName);
566 RtlFreeUnicodeString(&ArcName);
567 RtlFreeUnicodeString(&DeviceName);
568
569 /* Let caller know that we've found the boot CD */
570 return TRUE;
571 }
572
573 /* No boot CD found */
574 return FALSE;
575 }
576
577 NTSTATUS INIT_FUNCTION
578 IoCreateArcNames(VOID)
579 {
580 PCONFIGURATION_INFORMATION ConfigInfo;
581 ULONG i, RDiskNumber;
582 NTSTATUS Status;
583 LIST_ENTRY BiosDiskListHead;
584 LIST_ENTRY DiskListHead;
585 PLIST_ENTRY Entry;
586 PDISKENTRY BiosDiskEntry;
587 PDISKENTRY DiskEntry;
588 BOOLEAN FoundBoot;
589 PULONG Buffer;
590
591 ConfigInfo = IoGetConfigurationInformation();
592
593 /* create ARC names for hard disk drives */
594 InitializeListHead(&BiosDiskListHead);
595 InitializeListHead(&DiskListHead);
596 IopEnumerateBiosDisks(&BiosDiskListHead);
597 IopEnumerateDisks(&DiskListHead);
598
599 RDiskNumber = 0;
600 while (!IsListEmpty(&BiosDiskListHead))
601 {
602 Entry = RemoveHeadList(&BiosDiskListHead);
603 BiosDiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
604 Entry = DiskListHead.Flink;
605 while (Entry != &DiskListHead)
606 {
607 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
608 if (DiskEntry->Checksum == BiosDiskEntry->Checksum &&
609 DiskEntry->Signature == BiosDiskEntry->Signature)
610 {
611
612 Status = IopAssignArcNamesToDisk(DiskEntry->DeviceObject,
613 RDiskNumber,
614 DiskEntry->DiskNumber,
615 DiskEntry->PartitionCount,
616 &FoundBoot);
617
618 RemoveEntryList(&DiskEntry->ListEntry);
619 ExFreePool(DiskEntry);
620 break;
621 }
622 Entry = Entry->Flink;
623 }
624 RDiskNumber++;
625 ExFreePool(BiosDiskEntry);
626 }
627
628 while (!IsListEmpty(&DiskListHead))
629 {
630 Entry = RemoveHeadList(&DiskListHead);
631 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
632 ExFreePool(DiskEntry);
633 }
634
635 /* Check if we didn't find the boot disk */
636 if (!FoundBoot)
637 {
638 /* Allocate a buffer for the CD-ROM MBR */
639 Buffer = ExAllocatePoolWithTag(NonPagedPool, 2048, TAG_IO);
640 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
641
642 /* Loop every CD-ROM */
643 for (i = 0; i < ConfigInfo->CdRomCount; i++)
644 {
645 /* Give it an ARC name */
646 if (IopAssignArcNamesToCdrom(Buffer, i)) break;
647 }
648
649 /* Free the buffer */
650 ExFreePool(Buffer);
651 }
652
653 /* Return success */
654 return STATUS_SUCCESS;
655 }
656
657 NTSTATUS
658 NTAPI
659 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
660 OUT PANSI_STRING NtBootPath)
661 {
662 OBJECT_ATTRIBUTES ObjectAttributes;
663 NTSTATUS Status;
664 CHAR Buffer[256], AnsiBuffer[256];
665 WCHAR ArcNameBuffer[64];
666 ANSI_STRING TargetString, ArcString, TempString;
667 UNICODE_STRING LinkName, TargetName, ArcName;
668 HANDLE LinkHandle;
669
670 /* Create the Unicode name for the current ARC boot device */
671 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
672 RtlInitAnsiString(&TargetString, Buffer);
673 Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE);
674 if (!NT_SUCCESS(Status)) return FALSE;
675
676 /* Initialize the attributes and open the link */
677 InitializeObjectAttributes(&ObjectAttributes,
678 &TargetName,
679 OBJ_CASE_INSENSITIVE,
680 NULL,
681 NULL);
682 Status = NtOpenSymbolicLinkObject(&LinkHandle,
683 SYMBOLIC_LINK_ALL_ACCESS,
684 &ObjectAttributes);
685 if (!NT_SUCCESS(Status))
686 {
687 /* We failed, free the string */
688 RtlFreeUnicodeString(&TargetName);
689 return FALSE;
690 }
691
692 /* Query the current \\SystemRoot */
693 ArcName.Buffer = ArcNameBuffer;
694 ArcName.Length = 0;
695 ArcName.MaximumLength = sizeof(ArcNameBuffer);
696 Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL);
697 if (!NT_SUCCESS(Status))
698 {
699 /* We failed, free the string */
700 RtlFreeUnicodeString(&TargetName);
701 return FALSE;
702 }
703
704 /* Convert it to Ansi */
705 ArcString.Buffer = AnsiBuffer;
706 ArcString.Length = 0;
707 ArcString.MaximumLength = sizeof(AnsiBuffer);
708 Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE);
709 AnsiBuffer[ArcString.Length] = ANSI_NULL;
710
711 /* Close the link handle and free the name */
712 ObCloseHandle(LinkHandle, KernelMode);
713 RtlFreeUnicodeString(&TargetName);
714
715 /* Setup the system root name again */
716 RtlInitAnsiString(&TempString, "\\SystemRoot");
717 Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE);
718 if (!NT_SUCCESS(Status)) return FALSE;
719
720 /* Open the symbolic link for it */
721 InitializeObjectAttributes(&ObjectAttributes,
722 &LinkName,
723 OBJ_CASE_INSENSITIVE,
724 NULL,
725 NULL);
726 Status = NtOpenSymbolicLinkObject(&LinkHandle,
727 SYMBOLIC_LINK_ALL_ACCESS,
728 &ObjectAttributes);
729 if (!NT_SUCCESS(Status)) return FALSE;
730
731 /* Destroy it */
732 NtMakeTemporaryObject(LinkHandle);
733 ObCloseHandle(LinkHandle, KernelMode);
734
735 /* Now create the new name for it */
736 sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName);
737
738 /* Copy it into the passed parameter and null-terminate it */
739 RtlCopyString(NtBootPath, &ArcString);
740 Buffer[strlen(Buffer) - 1] = ANSI_NULL;
741
742 /* Setup the Unicode-name for the new symbolic link value */
743 RtlInitAnsiString(&TargetString, Buffer);
744 InitializeObjectAttributes(&ObjectAttributes,
745 &LinkName,
746 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
747 NULL,
748 NULL);
749 Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE);
750 if (!NT_SUCCESS(Status)) return FALSE;
751
752 /* Create it */
753 Status = NtCreateSymbolicLinkObject(&LinkHandle,
754 SYMBOLIC_LINK_ALL_ACCESS,
755 &ObjectAttributes,
756 &ArcName);
757
758 /* Free all the strings and close the handle and return success */
759 RtlFreeUnicodeString(&ArcName);
760 RtlFreeUnicodeString(&LinkName);
761 ObCloseHandle(LinkHandle, KernelMode);
762 return TRUE;
763 }
764
765 /* EOF */