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