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