- Fix IopApplyReactOSCdRomHack to handle LiveCD case properly. LiveCD should now...
[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 if (!(strstr(KeLoaderBlock->LoadOptions, "MININT")))
90 {
91 /* Build the name */
92 sprintf(p, "cdrom(%lu)", DeviceNumber);
93
94 /* Adjust original command line */
95 q = strchr(p, ')');
96 if (q)
97 {
98 q++;
99 strcpy(Buffer, q);
100 sprintf(p, "cdrom(%lu)", DeviceNumber);
101 strcat(p, Buffer);
102 }
103 }
104 }
105
106 /* Return whether this is the CD or not */
107 if (DeviceNumber != 1)
108 {
109 /* Hack until IoAssignDriveLetters is fixed */
110 swprintf(SharedUserData->NtSystemRoot, L"D:\\reactos");
111 return TRUE;
112 }
113
114 /* Failed */
115 return FALSE;
116 }
117
118 BOOLEAN
119 INIT_FUNCTION
120 NTAPI
121 IopGetDiskInformation(IN ULONG i,
122 OUT PULONG CheckSum,
123 OUT PULONG Signature,
124 OUT PULONG PartitionCount,
125 OUT PDEVICE_OBJECT *DiskDeviceObject)
126 {
127 ULONG j, Checksum;
128 ANSI_STRING TempString;
129 CHAR Buffer[128];
130 UNICODE_STRING DeviceName;
131 NTSTATUS Status;
132 PDEVICE_OBJECT DeviceObject;
133 PFILE_OBJECT FileObject;
134 DISK_GEOMETRY DiskGeometry;
135 PDRIVE_LAYOUT_INFORMATION DriveLayout;
136 KEVENT Event;
137 PIRP Irp;
138 IO_STATUS_BLOCK StatusBlock;
139 LARGE_INTEGER PartitionOffset;
140 PULONG PartitionBuffer;
141
142 /* Build the name */
143 sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", i);
144
145 /* Convert it to Unicode */
146 RtlInitAnsiString(&TempString, Buffer);
147 Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
148 if (!NT_SUCCESS(Status)) return FALSE;
149
150 /* Get the device pointer */
151 Status = IoGetDeviceObjectPointer(&DeviceName,
152 FILE_READ_DATA,
153 &FileObject,
154 &DeviceObject);
155 *DiskDeviceObject = DeviceObject;
156
157 /* Free the string */
158 RtlFreeUnicodeString(&DeviceName);
159
160 /* Move on if we failed */
161 if (!NT_SUCCESS(Status)) return FALSE;
162
163 /* Build an IRP to determine the sector size */
164 KeInitializeEvent(&Event, NotificationEvent, FALSE);
165 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
166 DeviceObject,
167 NULL,
168 0,
169 &DiskGeometry,
170 sizeof(DISK_GEOMETRY),
171 FALSE,
172 &Event,
173 &StatusBlock);
174 if (!Irp)
175 {
176 /* Try again */
177 ObDereferenceObject(FileObject);
178 return FALSE;
179 }
180
181 /* Call the driver and check if we have to wait on it */
182 Status = IoCallDriver(DeviceObject, Irp);
183 if (Status == STATUS_PENDING)
184 {
185 /* Wait on the driver */
186 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
187 Status = StatusBlock.Status;
188 }
189
190 /* Check if we failed */
191 if (!NT_SUCCESS(Status))
192 {
193 /* Try again */
194 ObDereferenceObject(FileObject);
195 return FALSE;
196 }
197
198 /* Read the partition table */
199 Status = IoReadPartitionTable(DeviceObject,
200 DiskGeometry.BytesPerSector,
201 TRUE,
202 &DriveLayout);
203
204 /* Dereference the file object */
205 ObDereferenceObject(FileObject);
206 if (!NT_SUCCESS(Status)) return FALSE;
207
208 /* Set the offset to 0 */
209 PartitionOffset.QuadPart = 0;
210
211 /* Allocate a buffer for the partition */
212 PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
213 DiskGeometry.BytesPerSector,
214 TAG_IO);
215 if (!PartitionBuffer) return FALSE;
216
217 /* Build an IRP to read the partition sector */
218 KeInitializeEvent(&Event, NotificationEvent, FALSE);
219 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
220 DeviceObject,
221 PartitionBuffer,
222 DiskGeometry.BytesPerSector,
223 &PartitionOffset,
224 &Event,
225 &StatusBlock);
226
227 /* Call the driver and check if we have to wait */
228 Status = IoCallDriver(DeviceObject, Irp);
229 if (Status == STATUS_PENDING)
230 {
231 /* Wait for completion */
232 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
233 Status = StatusBlock.Status;
234 }
235
236 /* Check if we failed */
237 if (!NT_SUCCESS(Status))
238 {
239 /* Try again */
240 ExFreePool(PartitionBuffer);
241 ExFreePool(DriveLayout);
242 return FALSE;
243 }
244
245 /* Calculate the MBR checksum */
246 Checksum = 0;
247 for (j = 0; j < 128; j++) Checksum += PartitionBuffer[j];
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 */