- Merge from trunk up to r45543
[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 if (KeRosLoaderBlock) goto freeldrhack;
358
359 /* Search if this device is the actual boot CD */
360 for (NextEntry = ArcDiskInfo->DiskSignatureListHead.Flink;
361 NextEntry != &ArcDiskInfo->DiskSignatureListHead;
362 NextEntry = NextEntry->Flink)
363 {
364 /* Get the current ARC disk signature entry */
365 ArcDiskEntry = CONTAINING_RECORD(NextEntry,
366 ARC_DISK_SIGNATURE,
367 ListEntry);
368 /* And check if checksums and arc names match */
369 if (CheckSum == ArcDiskEntry->CheckSum &&
370 strcmp(KeLoaderBlock->ArcBootDeviceName, ArcDiskEntry->ArcName) == 0)
371 {
372 IsBootCdRom = TRUE;
373 break;
374 }
375 }
376 goto checkbootcd;
377
378 freeldrhack:
379 /*
380 * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
381 * ARC Path name, and what happens here is a comparision of both checksums
382 * in order to see if this is the actual boot CD.
383 *
384 * In ReactOS this doesn't currently happen, instead we have a hack on top
385 * of this file which scans the CD for the ntoskrnl.exe file, then modifies
386 * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
387 * get the same state as if NTLDR had properly booted us, except that we do
388 * not actually need to check the signature, since the hack already did the
389 * check for ntoskrnl.exe, which is just as good.
390 *
391 * The signature code stays however, because eventually FreeLDR will work
392 * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
393 */
394 IsBootCdRom = IopApplyRosCdromArcHack(DiskNumber);
395
396 checkbootcd:
397 if (IsBootCdRom)
398 {
399 /* This is the boot CD-ROM, build the ARC name */
400 sprintf(ArcBuffer, "\\ArcName\\%s", KeLoaderBlock->ArcBootDeviceName);
401
402 /* Convert it to Unicode */
403 RtlInitAnsiString(&TempString, ArcBuffer);
404 Status = RtlAnsiStringToUnicodeString(&ArcName, &TempString, TRUE);
405 if (!NT_SUCCESS(Status)) return FALSE;
406
407 /* Create the symbolic link and free the strings */
408 IoAssignArcName(&ArcName, &DeviceName);
409 RtlFreeUnicodeString(&ArcName);
410 RtlFreeUnicodeString(&DeviceName);
411
412 /* Let caller know that we've found the boot CD */
413 return TRUE;
414 }
415
416 /* No boot CD found */
417 return FALSE;
418 }
419
420 NTSTATUS
421 INIT_FUNCTION
422 NTAPI
423 IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
424 {
425 PCONFIGURATION_INFORMATION ConfigInfo = IoGetConfigurationInformation();
426 PARC_DISK_INFORMATION ArcDiskInfo = LoaderBlock->ArcDiskInformation;
427 CHAR Buffer[128];
428 ANSI_STRING ArcBootString, ArcSystemString, ArcString;
429 UNICODE_STRING ArcName, BootPath, DeviceName;
430 BOOLEAN SingleDisk;
431 ULONG i, j, Length;
432 PDEVICE_OBJECT DeviceObject;
433 ULONG Signature, Checksum, PartitionCount;
434 PLIST_ENTRY NextEntry;
435 PARC_DISK_SIGNATURE ArcDiskEntry;
436 NTSTATUS Status;
437 BOOLEAN FoundBoot = FALSE;
438 PULONG PartitionBuffer;
439
440 /* Check if we only have one disk on the machine */
441 SingleDisk = ArcDiskInfo->DiskSignatureListHead.Flink->Flink ==
442 (&ArcDiskInfo->DiskSignatureListHead);
443
444 /* Create the global HAL partition name */
445 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcHalDeviceName);
446 RtlInitAnsiString(&ArcString, Buffer);
447 RtlAnsiStringToUnicodeString(&IoArcHalDeviceName, &ArcString, TRUE);
448
449 /* Create the global system partition name */
450 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
451 RtlInitAnsiString(&ArcString, Buffer);
452 RtlAnsiStringToUnicodeString(&IoArcBootDeviceName, &ArcString, TRUE);
453
454 /* Allocate memory for the string */
455 Length = strlen(LoaderBlock->ArcBootDeviceName) + sizeof(ANSI_NULL);
456 IoLoaderArcBootDeviceName = ExAllocatePoolWithTag(PagedPool,
457 Length,
458 TAG_IO);
459 if (IoLoaderArcBootDeviceName)
460 {
461 /* Copy the name */
462 RtlCopyMemory(IoLoaderArcBootDeviceName,
463 LoaderBlock->ArcBootDeviceName,
464 Length);
465 }
466
467 /* Check if we only found a disk, but we're booting from CD-ROM */
468 if ((SingleDisk) && strstr(LoaderBlock->ArcBootDeviceName, "cdrom"))
469 {
470 /* Then disable single-disk mode, since there's a CD drive out there */
471 SingleDisk = FALSE;
472 }
473
474 /* Build the boot strings */
475 RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName);
476 RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
477
478 /* Loop every detected disk */
479 for (i = 0; i < ConfigInfo->DiskCount; i++)
480 {
481 /* Get information about the disk */
482 if (!IopGetDiskInformation(i,
483 &Checksum,
484 &Signature,
485 &PartitionCount,
486 &DeviceObject))
487 {
488 /* Skip this disk */
489 continue;
490 }
491
492 /* Loop ARC disks */
493 for (NextEntry = ArcDiskInfo->DiskSignatureListHead.Flink;
494 NextEntry != &ArcDiskInfo->DiskSignatureListHead;
495 NextEntry = NextEntry->Flink)
496 {
497 /* Get the current ARC disk signature entry */
498 ArcDiskEntry = CONTAINING_RECORD(NextEntry,
499 ARC_DISK_SIGNATURE,
500 ListEntry);
501
502 /*
503 * Now check if the signature and checksum match, unless this is
504 * the only disk that was in the ARC list, and also in the device
505 * tree, in which case the check is bypassed and we accept the disk
506 */
507 if (((SingleDisk) && (ConfigInfo->DiskCount == 1)) ||
508 ((Checksum == ArcDiskEntry->CheckSum) &&
509 (Signature == ArcDiskEntry->Signature)))
510 {
511 /* Build the NT Device Name */
512 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", i);
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 ARC Device Name */
522 sprintf(Buffer, "\\ArcName\\%s", ArcDiskEntry->ArcName);
523
524 /* Convert it to Unicode */
525 RtlInitAnsiString(&ArcString, Buffer);
526 Status = RtlAnsiStringToUnicodeString(&ArcName,
527 &ArcString,
528 TRUE);
529 if (!NT_SUCCESS(Status)) continue;
530
531 /* Create the symbolic link and free the strings */
532 IoAssignArcName(&ArcName, &DeviceName);
533 RtlFreeUnicodeString(&ArcName);
534 RtlFreeUnicodeString(&DeviceName);
535
536 /* Loop all the partitions */
537 for (j = 0; j < PartitionCount; j++)
538 {
539 /* Build the partition device name */
540 sprintf(Buffer,
541 "\\Device\\Harddisk%lu\\Partition%lu",
542 i,
543 j + 1);
544
545 /* Convert it to Unicode */
546 RtlInitAnsiString(&ArcString, Buffer);
547 Status = RtlAnsiStringToUnicodeString(&DeviceName,
548 &ArcString,
549 TRUE);
550 if (!NT_SUCCESS(Status)) continue;
551
552 /* Build the partial ARC name for this partition */
553 sprintf(Buffer,
554 "%spartition(%lu)",
555 ArcDiskEntry->ArcName,
556 j + 1);
557 RtlInitAnsiString(&ArcString, Buffer);
558
559 /* Check if this is the boot device */
560 if (RtlEqualString(&ArcString, &ArcBootString, TRUE))
561 {
562 /* Remember that we found a Hard Disk Boot Device */
563 FoundBoot = TRUE;
564 }
565
566 /* Check if it's the system boot partition */
567 if (RtlEqualString(&ArcString, &ArcSystemString, TRUE))
568 {
569 /* It is, create a Unicode string for it */
570 RtlInitAnsiString(&ArcString,
571 LoaderBlock->NtHalPathName);
572 Status = RtlAnsiStringToUnicodeString(&BootPath,
573 &ArcString,
574 TRUE);
575 if (NT_SUCCESS(Status))
576 {
577 /* FIXME: Save in registry */
578
579 /* Free the string now */
580 RtlFreeUnicodeString(&BootPath);
581 }
582 }
583
584 /* Build the full ARC name */
585 sprintf(Buffer,
586 "\\ArcName\\%spartition(%lu)",
587 ArcDiskEntry->ArcName,
588 j + 1);
589
590 /* Convert it to Unicode */
591 RtlInitAnsiString(&ArcString, Buffer);
592 Status = RtlAnsiStringToUnicodeString(&ArcName,
593 &ArcString,
594 TRUE);
595 if (!NT_SUCCESS(Status)) continue;
596
597 /* Create the symbolic link and free the strings */
598 IoAssignArcName(&ArcName, &DeviceName);
599 RtlFreeUnicodeString(&ArcName);
600 RtlFreeUnicodeString(&DeviceName);
601 }
602 }
603 }
604 }
605
606 /* Check if we didn't find the boot disk */
607 if (!FoundBoot)
608 {
609 /* Allocate a buffer for the CD-ROM MBR */
610 PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool, 2048, TAG_IO);
611 if (!PartitionBuffer) return STATUS_INSUFFICIENT_RESOURCES;
612
613 /* Loop every CD-ROM */
614 for (i = 0; i < ConfigInfo->CdRomCount; i++)
615 {
616 /* Give it an ARC name */
617 if (IopAssignArcNamesToCdrom(LoaderBlock, PartitionBuffer, i)) break;
618 }
619
620 /* Free the buffer */
621 ExFreePoolWithTag(PartitionBuffer, TAG_IO);
622 }
623
624 /* Return success */
625 return STATUS_SUCCESS;
626 }
627
628 NTSTATUS
629 NTAPI
630 IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
631 OUT PANSI_STRING NtBootPath)
632 {
633 OBJECT_ATTRIBUTES ObjectAttributes;
634 NTSTATUS Status;
635 CHAR Buffer[256], AnsiBuffer[256];
636 WCHAR ArcNameBuffer[64];
637 ANSI_STRING TargetString, ArcString, TempString;
638 UNICODE_STRING LinkName, TargetName, ArcName;
639 HANDLE LinkHandle;
640
641 /* Create the Unicode name for the current ARC boot device */
642 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
643 RtlInitAnsiString(&TargetString, Buffer);
644 Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE);
645 if (!NT_SUCCESS(Status)) return FALSE;
646
647 /* Initialize the attributes and open the link */
648 InitializeObjectAttributes(&ObjectAttributes,
649 &TargetName,
650 OBJ_CASE_INSENSITIVE,
651 NULL,
652 NULL);
653 Status = NtOpenSymbolicLinkObject(&LinkHandle,
654 SYMBOLIC_LINK_ALL_ACCESS,
655 &ObjectAttributes);
656 if (!NT_SUCCESS(Status))
657 {
658 /* We failed, free the string */
659 RtlFreeUnicodeString(&TargetName);
660 return FALSE;
661 }
662
663 /* Query the current \\SystemRoot */
664 ArcName.Buffer = ArcNameBuffer;
665 ArcName.Length = 0;
666 ArcName.MaximumLength = sizeof(ArcNameBuffer);
667 Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL);
668 if (!NT_SUCCESS(Status))
669 {
670 /* We failed, free the string */
671 RtlFreeUnicodeString(&TargetName);
672 return FALSE;
673 }
674
675 /* Convert it to Ansi */
676 ArcString.Buffer = AnsiBuffer;
677 ArcString.Length = 0;
678 ArcString.MaximumLength = sizeof(AnsiBuffer);
679 Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE);
680 AnsiBuffer[ArcString.Length] = ANSI_NULL;
681
682 /* Close the link handle and free the name */
683 ObCloseHandle(LinkHandle, KernelMode);
684 RtlFreeUnicodeString(&TargetName);
685
686 /* Setup the system root name again */
687 RtlInitAnsiString(&TempString, "\\SystemRoot");
688 Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE);
689 if (!NT_SUCCESS(Status)) return FALSE;
690
691 /* Open the symbolic link for it */
692 InitializeObjectAttributes(&ObjectAttributes,
693 &LinkName,
694 OBJ_CASE_INSENSITIVE,
695 NULL,
696 NULL);
697 Status = NtOpenSymbolicLinkObject(&LinkHandle,
698 SYMBOLIC_LINK_ALL_ACCESS,
699 &ObjectAttributes);
700 if (!NT_SUCCESS(Status)) return FALSE;
701
702 /* Destroy it */
703 NtMakeTemporaryObject(LinkHandle);
704 ObCloseHandle(LinkHandle, KernelMode);
705
706 /* Now create the new name for it */
707 sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName);
708
709 /* Copy it into the passed parameter and null-terminate it */
710 RtlCopyString(NtBootPath, &ArcString);
711 Buffer[strlen(Buffer) - 1] = ANSI_NULL;
712
713 /* Setup the Unicode-name for the new symbolic link value */
714 RtlInitAnsiString(&TargetString, Buffer);
715 InitializeObjectAttributes(&ObjectAttributes,
716 &LinkName,
717 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
718 NULL,
719 NULL);
720 Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE);
721 if (!NT_SUCCESS(Status)) return FALSE;
722
723 /* Create it */
724 Status = NtCreateSymbolicLinkObject(&LinkHandle,
725 SYMBOLIC_LINK_ALL_ACCESS,
726 &ObjectAttributes,
727 &ArcName);
728
729 /* Free all the strings and close the handle and return success */
730 RtlFreeUnicodeString(&ArcName);
731 RtlFreeUnicodeString(&LinkName);
732 ObCloseHandle(LinkHandle, KernelMode);
733 return TRUE;
734 }
735
736 /* EOF */