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