ReactOS  0.4.14-dev-583-g2a1ba2c
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 
23 VOID
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;
36  PVOID Object;
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 */
46  ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink);
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 */
71  if (ObpLUIDDeviceMapsEnabled != 0)
72  {
73  DeviceMap = ObSystemDeviceMap;
74  }
75  /* Otherwise, use the one in the process */
76  else
77  {
78  DeviceMap = PsGetCurrentProcess()->DeviceMap;
79  }
80 
81 ReparseTargetPath:
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 
98  LocalTarget.Length -= ObpDosDevicesShortName.Length;
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  {
221  ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink);
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 */
275  switch(((PDEVICE_OBJECT)Object)->DeviceType)
276  {
279  break;
280  case FILE_DEVICE_CD_ROM:
283  break;
284  case FILE_DEVICE_DISK:
287  if (((PDEVICE_OBJECT)Object)->Characteristics & FILE_REMOVABLE_MEDIA)
289  else
291  break;
292  case FILE_DEVICE_NETWORK:
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] =
311  (UCHAR)DriveType;
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 
324 VOID
325 NTAPI
327 {
328  /* Just call the helper */
330 }
331 
332 VOID
333 NTAPI
335 {
336  WCHAR UpperDrive;
337  POBJECT_HEADER ObjectHeader;
338  POBJECT_HEADER_NAME_INFO ObjectNameInfo;
339 
340  /* Get header data */
341  ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink);
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 *--*/
389 VOID
390 NTAPI
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 *--*/
429 NTSTATUS
430 NTAPI
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,
461  ObjectType,
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;
489  return STATUS_REPARSE_OBJECT;
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)
507  return STATUS_NAME_TOO_LONG;
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;
533  return STATUS_REPARSE_OBJECT;
534  }
535 
536  /* FullPath is not enough, we'll have to reallocate */
537  MaximumLength = LengthUsed + sizeof(WCHAR);
538  NewTargetPath = ExAllocatePoolWithTag(NonPagedPool,
540  OB_NAME_TAG);
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;
576  return STATUS_REPARSE_OBJECT;
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] ==
593  (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
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)
605  return STATUS_NAME_TOO_LONG;
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,
614  OB_NAME_TAG);
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 *--*/
674 NTSTATUS
675 NTAPI
680 {
681  HANDLE hLink;
683  UNICODE_STRING CapturedLinkTarget;
686  PAGED_CODE();
687 
688  /* Check if we need to probe parameters */
689  if (PreviousMode != KernelMode)
690  {
691  _SEH2_TRY
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 */
738  PreviousMode,
739  NULL,
740  sizeof(OBJECT_SYMBOLIC_LINK),
741  0,
742  0,
743  (PVOID*)&SymbolicLink);
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 */
764  _SEH2_TRY
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  {
791  _SEH2_TRY
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 *--*/
829 NTSTATUS
830 NTAPI
834 {
835  HANDLE hLink;
838  PAGED_CODE();
839 
840  /* Check if we need to probe parameters */
841  if (PreviousMode != KernelMode)
842  {
843  _SEH2_TRY
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 */
859  PreviousMode,
860  NULL,
862  NULL,
863  &hLink);
864 
865  _SEH2_TRY
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 *--*/
901 NTSTATUS
902 NTAPI
906 {
907  UNICODE_STRING SafeLinkTarget = { 0, 0, NULL };
908  POBJECT_SYMBOLIC_LINK SymlinkObject;
911  ULONG LengthUsed;
912  PAGED_CODE();
913 
914  if (PreviousMode != KernelMode)
915  {
916  _SEH2_TRY
917  {
918  /* Probe the unicode string for read and write */
920 
921  /* Probe the unicode string's buffer for write */
922  SafeLinkTarget = *LinkTarget;
923  ProbeForWrite(SafeLinkTarget.Buffer,
924  SafeLinkTarget.MaximumLength,
925  sizeof(WCHAR));
926 
927  /* Probe the return length */
929  }
931  {
932  /* Return the exception code */
934  }
935  _SEH2_END;
936  }
937  else
938  {
939  /* No need to probe */
940  SafeLinkTarget = *LinkTarget;
941  }
942 
943  /* Reference the object */
944  Status = ObReferenceObjectByHandle(LinkHandle,
947  PreviousMode,
948  (PVOID *)&SymlinkObject,
949  NULL);
950  if (NT_SUCCESS(Status))
951  {
952  /* Lock the object */
954 
955  /*
956  * So here's the thing: If you specify a return length, then the
957  * implementation will use the maximum length. If you don't, then
958  * it will use the length.
959  */
960  LengthUsed = ResultLength ? SymlinkObject->LinkTarget.MaximumLength :
961  SymlinkObject->LinkTarget.Length;
962 
963  /* Enter SEH so we can safely copy */
964  _SEH2_TRY
965  {
966  /* Make sure our buffer will fit */
967  if (LengthUsed <= SafeLinkTarget.MaximumLength)
968  {
969  /* Copy the buffer */
970  RtlCopyMemory(SafeLinkTarget.Buffer,
971  SymlinkObject->LinkTarget.Buffer,
972  LengthUsed);
973 
974  /* Copy the new length */
975  LinkTarget->Length = SymlinkObject->LinkTarget.Length;
976  }
977  else
978  {
979  /* Otherwise set the failure status */
981  }
982 
983  /* In both cases, check if the required length was requested */
984  if (ResultLength)
985  {
986  /* Then return it */
987  *ResultLength = SymlinkObject->LinkTarget.MaximumLength;
988  }
989  }
991  {
992  /* Get the error code */
994  }
995  _SEH2_END;
996 
997  /* Unlock and dereference the object */
999  ObDereferenceObject(SymlinkObject);
1000  }
1001 
1002  /* Return query status */
1003  return Status;
1004 }
1005 
1006 /* EOF */
#define ProbeForWriteUlong(Ptr)
Definition: probe.h:36
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
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:2529
IN CINT OUT PVOID IN ULONG OUT PULONG ResultLength
Definition: conport.c:47
POBJECT_DIRECTORY Directory
Definition: obtypes.h:432
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
ObjectType
Definition: metafile.c:80
#define IN
Definition: typedefs.h:38
#define FILE_DEVICE_DISK
Definition: winioctl.h:112
#define TAG_SYMLINK_TARGET
Definition: tag.h:145
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
FORCEINLINE VOID ObpAcquireObjectLock(IN POBJECT_HEADER ObjectHeader)
Definition: ob_x.h:48
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define DOSDEVICE_DRIVE_REMOTE
Definition: obtypes.h:167
#define FILE_DEVICE_NETWORK
Definition: winioctl.h:123
Type
Definition: Type.h:6
#define DbgPrint
Definition: loader.c:25
USHORT MaximumLength
Definition: env_spec_w32.h:370
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
#define DOSDEVICE_DRIVE_RAMDISK
Definition: obtypes.h:169
struct _OBJECT_SYMBOLIC_LINK * POBJECT_SYMBOLIC_LINK
ULONG ObpLUIDDeviceMapsEnabled
Definition: devicemap.c:18
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
uint16_t * PWSTR
Definition: typedefs.h:54
DeviceType
Definition: mmdrv.h:41
FORCEINLINE VOID ObpReleaseObjectLock(IN POBJECT_HEADER ObjectHeader)
Definition: ob_x.h:84
#define FILE_DEVICE_FILE_SYSTEM
Definition: winioctl.h:114
LONG NTSTATUS
Definition: precomp.h:26
#define DOSDEVICE_DRIVE_CDROM
Definition: obtypes.h:168
UNICODE_STRING Name
Definition: obtypes.h:433
UINT DriveType
#define OBJECT_HEADER_TO_NAME_INFO(h)
Definition: obtypes.h:114
KPROCESSOR_MODE NTAPI ExGetPreviousMode(VOID)
Definition: sysinfo.c:3066
#define FILE_DEVICE_VIRTUAL_DISK
Definition: winioctl.h:141
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
NTSYSAPI WCHAR NTAPI RtlUpcaseUnicodeChar(WCHAR Source)
POBJECT_DIRECTORY ObpRootDirectoryObject
Definition: obname.c:19
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
#define PAGED_CODE()
Definition: video.h:57
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
_SEH2_TRY
Definition: create.c:4250
BOOLEAN DirectoryLocked
Definition: obtypes.h:516
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define OBJECT_TO_OBJECT_HEADER(o)
Definition: obtypes.h:111
#define FILE_DEVICE_CD_ROM
Definition: winioctl.h:107
ULONG DriveMap
Definition: obtypes.h:528
_Inout_ PUNICODE_STRING LinkTarget
Definition: zwfuncs.h:292
#define DOSDEVICE_DRIVE_REMOVABLE
Definition: obtypes.h:165
ALIGNEDNAME ObpDosDevicesShortNamePrefix
Definition: obname.c:23
ULARGE_INTEGER Alignment
Definition: ob.h:144
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:496
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define UNICODE_NULL
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
#define STATUS_REPARSE_OBJECT
Definition: ntstatus.h:102
_In_ PEPROCESS _In_ KPROCESSOR_MODE AccessMode
Definition: mmfuncs.h:396
#define DOSDEVICE_DRIVE_CALCULATE
Definition: obtypes.h:164
#define DOSDEVICE_DRIVE_UNKNOWN
Definition: obtypes.h:163
#define PsGetCurrentProcess
Definition: psfuncs.h:17
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
NTSTATUS NTAPI ObReferenceObjectByPointer(IN PVOID Object, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode)
Definition: obref.c:383
#define ProbeForWriteUnicodeString(Ptr)
Definition: probe.h:48
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:484
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:952
#define FILE_DEVICE_DISK_FILE_SYSTEM
Definition: winioctl.h:113
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
#define OB_NAME_TAG
Definition: tag.h:151
#define ObpDirectoryObjectType
Definition: ObTypes.c:123
#define STATUS_OBJECT_TYPE_MISMATCH
Definition: ntstatus.h:259
#define DOSDEVICE_DRIVE_FIXED
Definition: obtypes.h:166
#define _SEH2_YIELD(STMT_)
Definition: pseh2_64.h:8
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define ALIGN_DOWN(size, type)
Definition: umtypes.h:88
FORCEINLINE POBJECT_HEADER_NAME_INFO ObpReferenceNameInfo(IN POBJECT_HEADER ObjectHeader)
Definition: ob_x.h:102
#define ProbeForWriteHandle(Ptr)
Definition: probe.h:43
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
UCHAR DriveType[32]
Definition: obtypes.h:529
static IUnknown Object
Definition: main.c:512
_In_opt_ PVOID _In_opt_ PUNICODE_STRING _In_ PSECURITY_DESCRIPTOR _In_ PACCESS_STATE AccessState
Definition: sefuncs.h:414
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
UNICODE_STRING ObpDosDevicesShortName
Definition: obname.c:25
unsigned char UCHAR
Definition: xmlstorage.h:181
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
static const WCHAR L[]
Definition: oid.c:1250
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
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:414
PDEVICE_MAP ObSystemDeviceMap
Definition: obinit.c:46
Status
Definition: gdiplustypes.h:24
struct _DEVICE_MAP * DeviceMap
Definition: obtypes.h:418
FORCEINLINE VOID ObpReleaseLookupContext(IN POBP_LOOKUP_CONTEXT Context)
Definition: ob_x.h:255
UnicodeString MaximumLength
Definition: rtlfuncs.h:2982
_Must_inspect_result_ _In_ USHORT _In_ PHIDP_PREPARSED_DATA _Out_writes_to_ LengthAttributes PHIDP_EXTENDED_ATTRIBUTES Attributes
Definition: hidpi.h:348
_SEH2_END
Definition: create.c:4424
FORCEINLINE VOID ObpInitializeLookupContext(IN POBP_LOOKUP_CONTEXT Context)
Definition: ob_x.h:221
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:2932
LONG NTAPI ExSystemExceptionFilter(VOID)
Definition: harderr.c:351
unsigned short USHORT
Definition: pedump.c:61
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG _In_ PUNICODE_STRING _In_ PACCESS_MASK DesiredAccess
Definition: create.c:4157
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
#define STATUS_REPARSE
Definition: ntstatus.h:83
unsigned int * PULONG
Definition: retypes.h:1
#define FILE_DEVICE_NETWORK_FILE_SYSTEM
Definition: winioctl.h:125
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
#define ProbeForReadUnicodeString(Ptr)
Definition: probe.h:77
#define DPRINT1
Definition: precomp.h:8
#define OUT
Definition: typedefs.h:39
#define FILE_DEVICE_CD_ROM_FILE_SYSTEM
Definition: winioctl.h:108
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:390
unsigned int ULONG
Definition: retypes.h:1
#define SYMBOLIC_LINK_QUERY
Definition: nt_native.h:1265
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define ULONG_PTR
Definition: config.h:101
POBJECT_DIRECTORY DosDevicesDirectory
Definition: obtypes.h:525
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
KGUARDED_MUTEX ObpDeviceMapLock
Definition: oblife.c:24
FORCEINLINE VOID ObpDereferenceNameInfo(IN POBJECT_HEADER_NAME_INFO HeaderNameInfo)
Definition: ob_x.h:143
POBJECT_TYPE IoDeviceObjectType
Definition: iomgr.c:35
ULONG ACCESS_MASK
Definition: nt_native.h:40
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
static const WCHAR SymbolicLink[]
Definition: interface.c:31
_Inout_ PFCB _Inout_ PUNICODE_STRING RemainingName
Definition: cdprocs.h:806
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68