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