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