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