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