ReactOS 0.4.15-dev-7918-g2a2556c
oblink.c
Go to the documentation of this file.
1/*
2* PROJECT: ReactOS Kernel
3* LICENSE: GPL - See COPYING in the top level directory
4* FILE: ntoskrnl/ob/oblink.c
5* PURPOSE: Implements symbolic links
6* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7* David Welch (welch@mcmail.com)
8* Pierre Schweitzer
9*/
10
11/* INCLUDES *****************************************************************/
12
13#include <ntoskrnl.h>
14#define NDEBUG
15#include <debug.h>
16
17/* GLOBALS ******************************************************************/
18
20
21/* PRIVATE FUNCTIONS *********************************************************/
22
23VOID
25 IN BOOLEAN DeleteLink)
26{
27 PDEVICE_MAP DeviceMap;
28 UNICODE_STRING TargetPath, LocalTarget;
29 POBJECT_DIRECTORY NameDirectory, DirectoryObject;
30 ULONG MaxReparse;
31 OBP_LOOKUP_CONTEXT LookupContext;
33 POBJECT_HEADER ObjectHeader;
34 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
35 BOOLEAN DirectoryLocked;
37
38 /*
39 * To prevent endless reparsing, setting an upper limit on the
40 * number of reparses.
41 */
42 MaxReparse = 32;
43 NameDirectory = NULL;
44
45 /* Get header data */
47 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
48
49 /* Check if we have a directory in our symlink to use */
50 if (ObjectNameInfo != NULL)
51 {
52 NameDirectory = ObjectNameInfo->Directory;
53 }
54
55 /* Initialize lookup context */
56 ObpInitializeLookupContext(&LookupContext);
57
58 /*
59 * If we have to create the link, locate the IoDeviceObject if any
60 * this symbolic link points to.
61 */
62 if (SymbolicLink->LinkTargetObject != NULL || !DeleteLink)
63 {
64 /* Start the search from the root */
65 DirectoryObject = ObpRootDirectoryObject;
66
67 /* Keep track of our progress while parsing the name */
68 LocalTarget = SymbolicLink->LinkTarget;
69
70 /* If LUID mappings are enabled, use system map */
72 {
73 DeviceMap = ObSystemDeviceMap;
74 }
75 /* Otherwise, use the one in the process */
76 else
77 {
78 DeviceMap = PsGetCurrentProcess()->DeviceMap;
79 }
80
81ReparseTargetPath:
82 /*
83 * If we have a device map active, check whether we have a drive
84 * letter prefixed with ??, if so, chomp it
85 */
86 if (DeviceMap != NULL)
87 {
88 if (!((ULONG_PTR)(LocalTarget.Buffer) & 7))
89 {
90 if (DeviceMap->DosDevicesDirectory != NULL)
91 {
92 if (LocalTarget.Length >= ObpDosDevicesShortName.Length &&
93 (*(PULONGLONG)LocalTarget.Buffer ==
95 {
96 DirectoryObject = DeviceMap->DosDevicesDirectory;
97
99 LocalTarget.Buffer += (ObpDosDevicesShortName.Length / sizeof(WCHAR));
100 }
101 }
102 }
103 }
104
105 /* Try walking the target path and open each part of the path */
106 while (TRUE)
107 {
108 if (LocalTarget.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
109 {
110 ++LocalTarget.Buffer;
111 LocalTarget.Length -= sizeof(WCHAR);
112 }
113
114 /* Remember the current component of the target path */
115 TargetPath = LocalTarget;
116
117 /* Move forward to the next component of the target path */
118 if (LocalTarget.Length != 0)
119 {
120 do
121 {
122 if (LocalTarget.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
123 {
124 break;
125 }
126
127 ++LocalTarget.Buffer;
128 LocalTarget.Length -= sizeof(WCHAR);
129 }
130 while (LocalTarget.Length != 0);
131 }
132
133 TargetPath.Length -= LocalTarget.Length;
134
135 /*
136 * Finished processing the entire path, stop
137 * That's a failure case, we quit here
138 */
139 if (TargetPath.Length == 0)
140 {
141 ObpReleaseLookupContext(&LookupContext);
142 return;
143 }
144
145
146 /*
147 * Make sure a deadlock does not occur as an exclusive lock on a pushlock
148 * would have already taken one in ObpLookupObjectName() on the parent
149 * directory where the symlink is being created [ObInsertObject()].
150 * Prevent recursive locking by faking lock state in the lookup context
151 * when the current directory is same as the parent directory where
152 * the symlink is being created. If the lock state is not faked,
153 * ObpLookupEntryDirectory() will try to get a recursive lock on the
154 * pushlock and hang. For e.g. this happens when a substed drive is pointed to
155 * another substed drive.
156 */
157 if (DirectoryObject == NameDirectory)
158 {
159 DirectoryLocked = LookupContext.DirectoryLocked;
160 LookupContext.DirectoryLocked = TRUE;
161 }
162 else
163 {
164 DirectoryLocked = FALSE;
165 }
166
167 Object = ObpLookupEntryDirectory(DirectoryObject,
168 &TargetPath,
169 0,
170 FALSE,
171 &LookupContext);
172
173 /* Locking was faked, undo it now */
174 if (DirectoryObject == NameDirectory)
175 {
176 LookupContext.DirectoryLocked = DirectoryLocked;
177 }
178
179 /* Lookup failed, stop */
180 if (Object == NULL)
181 {
182 break;
183 }
184
185 /* If we don't have a directory object, we'll have to handle the object */
187 {
188 /* If that's not a symbolic link, stop here, nothing to do */
190 (((POBJECT_SYMBOLIC_LINK)Object)->DosDeviceDriveIndex != 0))
191 {
192 break;
193 }
194
195 /* We're out of reparse attempts */
196 if (MaxReparse == 0)
197 {
198 Object = NULL;
199 break;
200 }
201
202 --MaxReparse;
203
204 /* Symlink points to another initialized symlink, ask caller to reparse */
205 DirectoryObject = ObpRootDirectoryObject;
206
207 LocalTarget = ((POBJECT_SYMBOLIC_LINK)Object)->LinkTarget;
208
209 goto ReparseTargetPath;
210 }
211
212 /* Make this current directory, and continue search */
213 DirectoryObject = Object;
214 }
215 }
216
217 DeviceMap = NULL;
218 /* That's a drive letter, find a suitable device map */
219 if (SymbolicLink->DosDeviceDriveIndex != 0)
220 {
222 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
223 if (ObjectNameInfo != NULL)
224 {
225 if (ObjectNameInfo->Directory != NULL)
226 {
227 DeviceMap = ObjectNameInfo->Directory->DeviceMap;
228 }
229
230 ObpDereferenceNameInfo(ObjectNameInfo);
231 }
232 }
233
234 /* If we were asked to delete the symlink */
235 if (DeleteLink)
236 {
237 /* Zero its target */
238 RtlInitUnicodeString(&SymbolicLink->LinkTargetRemaining, NULL);
239
240 /* If we had a target objected, dereference it */
241 if (SymbolicLink->LinkTargetObject != NULL)
242 {
243 ObDereferenceObject(SymbolicLink->LinkTargetObject);
244 SymbolicLink->LinkTargetObject = NULL;
245 }
246
247 /* If it was a drive letter */
248 if (DeviceMap != NULL)
249 {
250 /* Acquire the device map lock */
252
253 /* Remove the drive entry */
254 DeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex - 1] =
256 DeviceMap->DriveMap &=
257 ~(1 << (SymbolicLink->DosDeviceDriveIndex - 1));
258
259 /* Release the device map lock */
261
262 /* Reset the drive index, valid drive index starts from 1 */
263 SymbolicLink->DosDeviceDriveIndex = 0;
264 }
265 }
266 else
267 {
269
270 /* If we have a drive letter and a pointer device object */
271 if (Object != NULL && SymbolicLink->DosDeviceDriveIndex != 0 &&
273 {
274 /* Calculate the drive type */
276 {
279 break;
283 break;
284 case FILE_DEVICE_DISK:
287 if (((PDEVICE_OBJECT)Object)->Characteristics & FILE_REMOVABLE_MEDIA)
289 else
291 break;
295 break;
296 default:
297 DPRINT1("Device Type %lu for %wZ is not known or unhandled\n",
299 &SymbolicLink->LinkTarget);
301 }
302 }
303
304 /* Add a new drive entry */
305 if (DeviceMap != NULL)
306 {
307 /* Acquire the device map lock */
309
310 DeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex - 1] =
312 DeviceMap->DriveMap |=
313 1 << (SymbolicLink->DosDeviceDriveIndex - 1);
314
315 /* Release the device map lock */
317 }
318 }
319
320 /* Cleanup */
321 ObpReleaseLookupContext(&LookupContext);
322}
323
324VOID
325NTAPI
327{
328 /* Just call the helper */
330}
331
332VOID
333NTAPI
335{
336 WCHAR UpperDrive;
337 POBJECT_HEADER ObjectHeader;
338 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
339
340 /* Get header data */
342 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
343
344 /* No name info, nothing to create */
345 if (ObjectNameInfo == NULL)
346 {
347 return;
348 }
349
350 /* If we have a device map, look for creating a letter based drive */
351 if (ObjectNameInfo->Directory != NULL &&
352 ObjectNameInfo->Directory->DeviceMap != NULL)
353 {
354 /* Is it a drive letter based name? */
355 if (ObjectNameInfo->Name.Length == 2 * sizeof(WCHAR))
356 {
357 if (ObjectNameInfo->Name.Buffer[1] == L':')
358 {
359 UpperDrive = RtlUpcaseUnicodeChar(ObjectNameInfo->Name.Buffer[0]);
360 if (UpperDrive >= L'A' && UpperDrive <= L'Z')
361 {
362 /* Compute its index (it's 1 based - 0 means no letter) */
363 SymbolicLink->DosDeviceDriveIndex = UpperDrive - (L'A' - 1);
364 }
365 }
366 }
367
368 /* Call the helper */
370 }
371
372 /* We're done */
373 ObpDereferenceNameInfo(ObjectNameInfo);
374}
375
376/*++
377* @name ObpDeleteSymbolicLink
378*
379* The ObpDeleteSymbolicLink routine <FILLMEIN>
380*
381* @param ObjectBody
382* <FILLMEIN>
383*
384* @return None.
385*
386* @remarks None.
387*
388*--*/
389VOID
390NTAPI
392{
393 POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ObjectBody;
394
395 /* Make sure that the symbolic link has a name */
396 if (SymlinkObject->LinkTarget.Buffer)
397 {
398 /* Free the name */
399 ExFreePool(SymlinkObject->LinkTarget.Buffer);
400 SymlinkObject->LinkTarget.Buffer = NULL;
401 }
402}
403
404/*++
405* @name ObpParseSymbolicLink
406*
407* The ObpParseSymbolicLink routine <FILLMEIN>
408*
409* @param Object
410* <FILLMEIN>
411*
412* @param NextObject
413* <FILLMEIN>
414*
415* @param FullPath
416* <FILLMEIN>
417*
418* @param RemainingPath
419* <FILLMEIN>
420*
421* @param Attributes
422* <FILLMEIN>
423*
424* @return STATUS_SUCCESS or appropriate error value.
425*
426* @remarks None.
427*
428*--*/
430NTAPI
436 IN OUT PUNICODE_STRING FullPath,
440 OUT PVOID *NextObject)
441{
442 POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ParsedObject;
443 PUNICODE_STRING TargetPath;
444 PWSTR NewTargetPath;
445 ULONG LengthUsed, MaximumLength, TempLength;
447 PAGED_CODE();
448
449 /* Assume failure */
450 *NextObject = NULL;
451
452 /* Check if we're out of name to parse */
453 if (!RemainingName->Length)
454 {
455 /* Check if we got an object type */
456 if (ObjectType)
457 {
458 /* Reference the object only */
459 Status = ObReferenceObjectByPointer(ParsedObject,
460 0,
462 AccessMode);
463 if (NT_SUCCESS(Status))
464 {
465 /* Return it */
466 *NextObject = ParsedObject;
467 }
468
470 {
471 /* Fail */
472 return Status;
473 }
474 }
475 }
476 else if (RemainingName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)
477 {
478 /* Symbolic links must start with a backslash */
480 }
481
482 /* Check if this symlink is bound to a specific object */
483 if (SymlinkObject->LinkTargetObject)
484 {
485 /* No name to reparse, directly reparse the object */
486 if (!SymlinkObject->LinkTargetRemaining.Length)
487 {
488 *NextObject = SymlinkObject->LinkTargetObject;
490 }
491
492 TempLength = SymlinkObject->LinkTargetRemaining.Length;
493 /* The target and remaining names aren't empty, so check for slashes */
494 if (SymlinkObject->LinkTargetRemaining.Buffer[TempLength / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR &&
496 {
497 /* Reduce the length by one to cut off the extra '\' */
498 TempLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
499 }
500
501 /* Calculate the new length */
502 LengthUsed = TempLength + RemainingName->Length;
503 LengthUsed += (sizeof(WCHAR) * (RemainingName->Buffer - FullPath->Buffer));
504
505 /* Check if it's not too much */
506 if (LengthUsed > 0xFFF0)
508
509 /* If FullPath is enough, use it */
510 if (FullPath->MaximumLength > LengthUsed)
511 {
512 /* Update remaining length if appropriate */
513 if (RemainingName->Length)
514 {
515 RtlMoveMemory((PVOID)((ULONG_PTR)RemainingName->Buffer + TempLength),
516 RemainingName->Buffer,
517 RemainingName->Length);
518 }
519
520 /* And move the target object name */
522 SymlinkObject->LinkTargetRemaining.Buffer,
523 TempLength);
524
525 /* Finally update the full path with what we parsed */
526 FullPath->Length += SymlinkObject->LinkTargetRemaining.Length;
527 RemainingName->Length += SymlinkObject->LinkTargetRemaining.Length;
528 RemainingName->MaximumLength += RemainingName->Length + sizeof(WCHAR);
529 FullPath->Buffer[FullPath->Length / sizeof(WCHAR)] = UNICODE_NULL;
530
531 /* And reparse */
532 *NextObject = SymlinkObject->LinkTargetObject;
534 }
535
536 /* FullPath is not enough, we'll have to reallocate */
537 MaximumLength = LengthUsed + sizeof(WCHAR);
538 NewTargetPath = ExAllocatePoolWithTag(NonPagedPool,
541 if (!NewTargetPath) return STATUS_INSUFFICIENT_RESOURCES;
542
543 /* Copy path begin */
544 RtlCopyMemory(NewTargetPath,
545 FullPath->Buffer,
546 sizeof(WCHAR) * (RemainingName->Buffer - FullPath->Buffer));
547
548 /* Copy path end (if any) */
549 if (RemainingName->Length)
550 {
551 RtlCopyMemory((PVOID)((ULONG_PTR)&NewTargetPath[RemainingName->Buffer - FullPath->Buffer] + TempLength),
552 RemainingName->Buffer,
553 RemainingName->Length);
554 }
555
556 /* And finish path with bound object */
557 RtlCopyMemory(&NewTargetPath[RemainingName->Buffer - FullPath->Buffer],
558 SymlinkObject->LinkTargetRemaining.Buffer,
559 TempLength);
560
561 /* Free old buffer */
562 ExFreePool(FullPath->Buffer);
563
564 /* Set new buffer in FullPath */
565 FullPath->Buffer = NewTargetPath;
566 FullPath->MaximumLength = MaximumLength;
567 FullPath->Length = LengthUsed;
568
569 /* Update remaining with what we handled */
570 RemainingName->Length = LengthUsed + (ULONG_PTR)NewTargetPath - (ULONG_PTR)&NewTargetPath[RemainingName->Buffer - FullPath->Buffer];
571 RemainingName->Buffer = &NewTargetPath[RemainingName->Buffer - FullPath->Buffer];
572 RemainingName->MaximumLength = RemainingName->Length + sizeof(WCHAR);
573
574 /* Reparse! */
575 *NextObject = SymlinkObject->LinkTargetObject;
577 }
578
579 /* Set the target path and length */
580 TargetPath = &SymlinkObject->LinkTarget;
581 TempLength = TargetPath->Length;
582
583 /*
584 * Strip off the extra trailing '\', if we don't do this we will end up
585 * adding a extra '\' between TargetPath and RemainingName
586 * causing caller's like ObpLookupObjectName() to fail.
587 */
588 if (TempLength && RemainingName->Length)
589 {
590 /* The target and remaining names aren't empty, so check for slashes */
591 if ((TargetPath->Buffer[TempLength / sizeof(WCHAR) - 1] ==
594 {
595 /* Reduce the length by one to cut off the extra '\' */
596 TempLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
597 }
598 }
599
600 /* Calculate the new length */
601 LengthUsed = TempLength + RemainingName->Length;
602
603 /* Check if it's not too much */
604 if (LengthUsed > 0xFFF0)
606
607 /* Optimization: check if the new name is shorter */
608 if (FullPath->MaximumLength <= LengthUsed)
609 {
610 /* It's not, allocate a new one */
611 MaximumLength = LengthUsed + sizeof(WCHAR);
612 NewTargetPath = ExAllocatePoolWithTag(NonPagedPool,
615 if (!NewTargetPath) return STATUS_INSUFFICIENT_RESOURCES;
616 }
617 else
618 {
619 /* It is! Reuse the name... */
620 MaximumLength = FullPath->MaximumLength;
621 NewTargetPath = FullPath->Buffer;
622 }
623
624 /* Make sure we have a length */
625 if (RemainingName->Length)
626 {
627 /* Copy the new path */
628 RtlMoveMemory((PVOID)((ULONG_PTR)NewTargetPath + TempLength),
629 RemainingName->Buffer,
630 RemainingName->Length);
631 }
632
633 /* Copy the target path and null-terminate it */
634 RtlCopyMemory(NewTargetPath, TargetPath->Buffer, TempLength);
635 NewTargetPath[LengthUsed / sizeof(WCHAR)] = UNICODE_NULL;
636
637 /* If the optimization didn't work, free the old buffer */
638 if (NewTargetPath != FullPath->Buffer) ExFreePool(FullPath->Buffer);
639
640 /* Update the path values */
641 FullPath->Length = (USHORT)LengthUsed;
642 FullPath->MaximumLength = (USHORT)MaximumLength;
643 FullPath->Buffer = NewTargetPath;
644
645 /* Tell the parse routine to start reparsing */
646 return STATUS_REPARSE;
647}
648
649/* PUBLIC FUNCTIONS **********************************************************/
650
651/*++
652* @name NtCreateSymbolicLinkObject
653* @implemented NT4
654*
655* The NtCreateSymbolicLinkObject opens or creates a symbolic link object.
656*
657* @param LinkHandle
658* Variable which receives the symlink handle.
659*
660* @param DesiredAccess
661* Desired access to the symlink.
662*
663* @param ObjectAttributes
664* Structure describing the symlink.
665*
666* @param LinkTarget
667* Unicode string defining the symlink's target
668*
669* @return STATUS_SUCCESS or appropriate error value.
670*
671* @remarks None.
672*
673*--*/
675NTAPI
680{
681 HANDLE hLink;
683 UNICODE_STRING CapturedLinkTarget;
686 PAGED_CODE();
687
688 /* Check if we need to probe parameters */
690 {
692 {
693 /* Probe the target */
694 CapturedLinkTarget = ProbeForReadUnicodeString(LinkTarget);
695 ProbeForRead(CapturedLinkTarget.Buffer,
696 CapturedLinkTarget.MaximumLength,
697 sizeof(WCHAR));
698
699 /* Probe the return handle */
700 ProbeForWriteHandle(LinkHandle);
701 }
703 {
704 /* Return the exception code */
706 }
707 _SEH2_END;
708 }
709 else
710 {
711 /* No need to capture */
712 CapturedLinkTarget = *LinkTarget;
713 }
714
715 /* Check if the maximum length is odd */
716 if (CapturedLinkTarget.MaximumLength % sizeof(WCHAR))
717 {
718 /* Round it down */
719 CapturedLinkTarget.MaximumLength =
720 (USHORT)ALIGN_DOWN(CapturedLinkTarget.MaximumLength, WCHAR);
721 }
722
723 /* Fail if the length is odd, or if the maximum is smaller or 0 */
724 if ((CapturedLinkTarget.Length % sizeof(WCHAR)) ||
725 (CapturedLinkTarget.MaximumLength < CapturedLinkTarget.Length) ||
726 !(CapturedLinkTarget.MaximumLength))
727 {
728 /* This message is displayed on the debugger in Windows */
729 DbgPrint("OB: Invalid symbolic link target - %wZ\n",
730 &CapturedLinkTarget);
732 }
733
734 /* Create the object */
739 NULL,
740 sizeof(OBJECT_SYMBOLIC_LINK),
741 0,
742 0,
744 if (NT_SUCCESS(Status))
745 {
746 /* Success! Fill in the creation time immediately */
747 KeQuerySystemTime(&SymbolicLink->CreationTime);
748
749 /* Setup the target name */
750 SymbolicLink->LinkTarget.Length = CapturedLinkTarget.Length;
751 SymbolicLink->LinkTarget.MaximumLength = CapturedLinkTarget.MaximumLength;
752 SymbolicLink->LinkTarget.Buffer =
754 CapturedLinkTarget.MaximumLength,
756 if (!SymbolicLink->LinkTarget.Buffer)
757 {
758 /* Dereference the symbolic link object and fail */
760 return STATUS_NO_MEMORY;
761 }
762
763 /* Copy it */
765 {
766 RtlCopyMemory(SymbolicLink->LinkTarget.Buffer,
767 CapturedLinkTarget.Buffer,
768 CapturedLinkTarget.MaximumLength);
769 }
771 {
774 }
775 _SEH2_END;
776
777 /* Initialize the remaining name, dos drive index and target object */
778 SymbolicLink->LinkTargetObject = NULL;
779 SymbolicLink->DosDeviceDriveIndex = 0;
780 RtlInitUnicodeString(&SymbolicLink->LinkTargetRemaining, NULL);
781
782 /* Insert it into the object tree */
784 NULL,
786 0,
787 NULL,
788 &hLink);
789 if (NT_SUCCESS(Status))
790 {
792 {
793 /* Return the handle to caller */
794 *LinkHandle = hLink;
795 }
797 {
798 /* Get exception code */
800 }
801 _SEH2_END;
802 }
803 }
804
805 /* Return status to caller */
806 return Status;
807}
808
809/*++
810* @name NtOpenSymbolicLinkObject
811* @implemented NT4
812*
813* The NtOpenSymbolicLinkObject opens a symbolic link object.
814*
815* @param LinkHandle
816* Variable which receives the symlink handle.
817*
818* @param DesiredAccess
819* Desired access to the symlink.
820*
821* @param ObjectAttributes
822* Structure describing the symlink.
823*
824* @return STATUS_SUCCESS or appropriate error value.
825*
826* @remarks None.
827*
828*--*/
830NTAPI
834{
835 HANDLE hLink;
838 PAGED_CODE();
839
840 /* Check if we need to probe parameters */
842 {
844 {
845 /* Probe the return handle */
846 ProbeForWriteHandle(LinkHandle);
847 }
849 {
850 /* Return the exception code */
852 }
853 _SEH2_END;
854 }
855
856 /* Open the object */
860 NULL,
862 NULL,
863 &hLink);
864
866 {
867 /* Return the handle to caller */
868 *LinkHandle = hLink;
869 }
871 {
872 /* Get exception code */
874 }
875 _SEH2_END;
876
877 /* Return status to caller */
878 return Status;
879}
880
881/*++
882* @name NtQuerySymbolicLinkObject
883* @implemented NT4
884*
885* The NtQuerySymbolicLinkObject queries a symbolic link object.
886*
887* @param LinkHandle
888* Symlink handle to query
889*
890* @param LinkTarget
891* Unicode string defining the symlink's target
892*
893* @param ResultLength
894* Caller supplied storage for the number of bytes written (or NULL).
895*
896* @return STATUS_SUCCESS or appropriate error value.
897*
898* @remarks None.
899*
900*--*/
902NTAPI
906{
908 UNICODE_STRING SafeLinkTarget = { 0, 0, NULL };
909 POBJECT_SYMBOLIC_LINK SymlinkObject;
910 POBJECT_HEADER ObjectHeader;
911 ULONG LengthUsed;
913
914 PAGED_CODE();
915
917 {
919 {
920 /* Probe the unicode string for read and write */
922
923 /* Probe the unicode string's buffer for write */
924 SafeLinkTarget = *LinkTarget;
925 ProbeForWrite(SafeLinkTarget.Buffer,
926 SafeLinkTarget.MaximumLength,
927 sizeof(WCHAR));
928
929 /* Probe the return length */
931 }
933 {
934 /* Return the exception code */
936 }
937 _SEH2_END;
938 }
939 else
940 {
941 /* No need to probe */
942 SafeLinkTarget = *LinkTarget;
943 }
944
945 /* Reference the object */
950 (PVOID*)&SymlinkObject,
951 NULL);
952 if (NT_SUCCESS(Status))
953 {
954 /* Get the object header */
955 ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymlinkObject);
956
957 /* Lock the object */
958 ObpAcquireObjectLock(ObjectHeader);
959
960 /*
961 * So here's the thing: If you specify a return length, then the
962 * implementation will use the maximum length. If you don't, then
963 * it will use the length.
964 */
965 LengthUsed = ResultLength ? SymlinkObject->LinkTarget.MaximumLength :
966 SymlinkObject->LinkTarget.Length;
967
968 /* Enter SEH so we can safely copy */
970 {
971 /* Make sure our buffer will fit */
972 if (LengthUsed <= SafeLinkTarget.MaximumLength)
973 {
974 /* Copy the buffer */
975 RtlCopyMemory(SafeLinkTarget.Buffer,
976 SymlinkObject->LinkTarget.Buffer,
977 LengthUsed);
978
979 /* Copy the new length */
980 LinkTarget->Length = SymlinkObject->LinkTarget.Length;
981 }
982 else
983 {
984 /* Otherwise set the failure status */
986 }
987
988 /* In both cases, check if the required length was requested */
989 if (ResultLength)
990 {
991 /* Then return it */
992 *ResultLength = SymlinkObject->LinkTarget.MaximumLength;
993 }
994 }
996 {
997 /* Get the error code */
999 }
1000 _SEH2_END;
1001
1002 /* Unlock and dereference the object */
1003 ObpReleaseObjectLock(ObjectHeader);
1004 ObDereferenceObject(SymlinkObject);
1005 }
1006
1007 /* Return query status */
1008 return Status;
1009}
1010
1011/* EOF */
#define PAGED_CODE()
UINT DriveType
#define ObpDirectoryObjectType
Definition: ObTypes.c:118
unsigned char BOOLEAN
Type
Definition: Type.h:7
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
_Inout_ PFCB _Inout_ PUNICODE_STRING RemainingName
Definition: cdprocs.h:802
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static const WCHAR SymbolicLink[]
Definition: interface.c:31
#define ULONG_PTR
Definition: config.h:101
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define NonPagedPool
Definition: env_spec_w32.h:307
#define PagedPool
Definition: env_spec_w32.h:308
#define ExGetPreviousMode
Definition: ex.h:140
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
Status
Definition: gdiplustypes.h:25
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
#define DbgPrint
Definition: hal.h:12
LONG NTAPI ExSystemExceptionFilter(VOID)
Definition: harderr.c:349
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
POBJECT_TYPE IoDeviceObjectType
Definition: iomgr.c:35
DeviceType
Definition: mmdrv.h:42
ObjectType
Definition: metafile.c:81
#define KernelMode
Definition: asm.h:34
struct _OBJECT_SYMBOLIC_LINK * POBJECT_SYMBOLIC_LINK
#define DOSDEVICE_DRIVE_UNKNOWN
Definition: obtypes.h:163
#define DOSDEVICE_DRIVE_RAMDISK
Definition: obtypes.h:169
#define OBJECT_HEADER_TO_NAME_INFO(h)
Definition: obtypes.h:114
#define DOSDEVICE_DRIVE_FIXED
Definition: obtypes.h:166
#define DOSDEVICE_DRIVE_CALCULATE
Definition: obtypes.h:164
#define DOSDEVICE_DRIVE_REMOTE
Definition: obtypes.h:167
#define OBJECT_TO_OBJECT_HEADER(o)
Definition: obtypes.h:111
#define DOSDEVICE_DRIVE_CDROM
Definition: obtypes.h:168
#define DOSDEVICE_DRIVE_REMOVABLE
Definition: obtypes.h:165
WCHAR NTAPI RtlUpcaseUnicodeChar(_In_ WCHAR Source)
Definition: nlsboot.c:176
#define SYMBOLIC_LINK_QUERY
Definition: nt_native.h:1265
ULONG ACCESS_MASK
Definition: nt_native.h:40
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:383
#define UNICODE_NULL
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
#define STATUS_REPARSE
Definition: ntstatus.h:83
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
#define STATUS_REPARSE_OBJECT
Definition: ntstatus.h:102
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:498
#define STATUS_OBJECT_TYPE_MISMATCH
Definition: ntstatus.h:273
#define L(x)
Definition: ntvdm.h:50
ALIGNEDNAME ObpDosDevicesShortNamePrefix
Definition: obname.c:23
UNICODE_STRING ObpDosDevicesShortName
Definition: obname.c:25
PVOID NTAPI ObpLookupEntryDirectory(IN POBJECT_DIRECTORY Directory, IN PUNICODE_STRING Name, IN ULONG Attributes, IN UCHAR SearchShadow, IN POBP_LOOKUP_CONTEXT Context)
Definition: obdir.c:158
KGUARDED_MUTEX ObpDeviceMapLock
Definition: oblife.c:24
POBJECT_DIRECTORY ObpRootDirectoryObject
Definition: obname.c:19
ULONG ObpLUIDDeviceMapsEnabled
Definition: devicemap.c:18
FORCEINLINE VOID ObpAcquireObjectLock(IN POBJECT_HEADER ObjectHeader)
Definition: ob_x.h:48
FORCEINLINE VOID ObpInitializeLookupContext(IN POBP_LOOKUP_CONTEXT Context)
Initializes a new object directory lookup context. Used for lookup operations (insertions/deletions) ...
Definition: ob_x.h:258
FORCEINLINE VOID ObpReleaseObjectLock(IN POBJECT_HEADER ObjectHeader)
Definition: ob_x.h:84
FORCEINLINE VOID ObpDereferenceNameInfo(IN POBJECT_HEADER_NAME_INFO HeaderNameInfo)
Definition: ob_x.h:143
FORCEINLINE VOID ObpReleaseLookupContext(IN POBP_LOOKUP_CONTEXT Context)
Releases an initialized object directory lookup context. Unlocks it if necessary, and dereferences th...
Definition: ob_x.h:323
FORCEINLINE POBJECT_HEADER_NAME_INFO ObpReferenceNameInfo(IN POBJECT_HEADER ObjectHeader)
Definition: ob_x.h:102
NTSTATUS NTAPI ObInsertObject(IN PVOID Object, IN PACCESS_STATE AccessState OPTIONAL, IN ACCESS_MASK DesiredAccess, IN ULONG ObjectPointerBias, OUT PVOID *NewObject OPTIONAL, OUT PHANDLE Handle)
Definition: obhandle.c:2935
NTSTATUS NTAPI ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, IN PACCESS_STATE PassedAccessState, IN ACCESS_MASK DesiredAccess, IN OUT PVOID ParseContext, OUT PHANDLE Handle)
Definition: obhandle.c:2532
PDEVICE_MAP ObSystemDeviceMap
Definition: obinit.c:46
NTSTATUS NTAPI ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, IN POBJECT_TYPE Type, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, IN ULONG ObjectSize, IN ULONG PagedPoolCharge OPTIONAL, IN ULONG NonPagedPoolCharge OPTIONAL, OUT PVOID *Object)
Definition: oblife.c:1039
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
NTSTATUS NTAPI ObReferenceObjectByPointer(IN PVOID Object, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode)
Definition: obref.c:381
unsigned short USHORT
Definition: pedump.c:61
#define FILE_DEVICE_FILE_SYSTEM
Definition: winioctl.h:115
#define FILE_DEVICE_DISK_FILE_SYSTEM
Definition: winioctl.h:114
#define FILE_DEVICE_CD_ROM
Definition: winioctl.h:108
#define FILE_DEVICE_CD_ROM_FILE_SYSTEM
Definition: winioctl.h:109
#define FILE_DEVICE_NETWORK_FILE_SYSTEM
Definition: winioctl.h:126
#define FILE_DEVICE_NETWORK
Definition: winioctl.h:124
#define FILE_DEVICE_DISK
Definition: winioctl.h:113
#define FILE_DEVICE_VIRTUAL_DISK
Definition: winioctl.h:142
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#define ProbeForWriteUnicodeString(Ptr)
Definition: probe.h:48
#define ProbeForWriteHandle(Ptr)
Definition: probe.h:43
#define ProbeForWriteUlong(Ptr)
Definition: probe.h:36
#define ProbeForReadUnicodeString(Ptr)
Definition: probe.h:77
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
UCHAR DriveType[32]
Definition: obtypes.h:529
POBJECT_DIRECTORY DosDevicesDirectory
Definition: obtypes.h:525
ULONG DriveMap
Definition: obtypes.h:528
struct _DEVICE_MAP * DeviceMap
Definition: obtypes.h:418
POBJECT_DIRECTORY Directory
Definition: obtypes.h:432
UNICODE_STRING Name
Definition: obtypes.h:433
BOOLEAN DirectoryLocked
Definition: obtypes.h:516
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define OB_NAME_TAG
Definition: tag.h:118
#define TAG_SYMLINK_TARGET
Definition: tag.h:124
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define ALIGN_DOWN(size, type)
Definition: umtypes.h:88
ULARGE_INTEGER Alignment
Definition: ob.h:154
_Must_inspect_result_ _In_ WDFCOLLECTION _In_ WDFOBJECT Object
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3776
_Must_inspect_result_ _In_ WDFDEVICE _In_ ULONG _In_ ACCESS_MASK DesiredAccess
Definition: wdfdevice.h:2658
_In_ WDFDMATRANSACTION _In_ size_t MaximumLength
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
_In_ PEPROCESS _In_ KPROCESSOR_MODE AccessMode
Definition: mmfuncs.h:396
#define ObDereferenceObject
Definition: obfuncs.h:203
#define PsGetCurrentProcess
Definition: psfuncs.h:17
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
_In_opt_ PVOID _In_opt_ PUNICODE_STRING _In_ PSECURITY_DESCRIPTOR _In_ PACCESS_STATE AccessState
Definition: sefuncs.h:417
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180
_Inout_ PUNICODE_STRING LinkTarget
Definition: zwfuncs.h:292