ReactOS  0.4.11-dev-465-g0e6bc23
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 */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ******************************************************************/
17 
19 
20 /* PRIVATE FUNCTIONS *********************************************************/
21 
22 VOID
23 NTAPI
25 {
26  POBJECT_HEADER ObjectHeader;
27  POBJECT_HEADER_NAME_INFO ObjectNameInfo;
28 
29  /* FIXME: Need to support Device maps */
30 
31  /* Get header data */
32  ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink);
33  ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
34 
35  /* Check if we are not actually in a directory with a device map */
36  if (!(ObjectNameInfo) ||
37  !(ObjectNameInfo->Directory) /*||
38  !(ObjectNameInfo->Directory->DeviceMap)*/)
39  {
40  ObpDereferenceNameInfo(ObjectNameInfo);
41  return;
42  }
43 
44  /* Check if it's a DOS drive letter, and remove the entry from drive map if needed */
45  if (SymbolicLink->DosDeviceDriveIndex != 0 &&
46  ObjectNameInfo->Name.Length == 2 * sizeof(WCHAR) &&
47  ObjectNameInfo->Name.Buffer[1] == L':' &&
48  ( (ObjectNameInfo->Name.Buffer[0] >= L'A' &&
49  ObjectNameInfo->Name.Buffer[0] <= L'Z') ||
50  (ObjectNameInfo->Name.Buffer[0] >= L'a' &&
51  ObjectNameInfo->Name.Buffer[0] <= L'z') ))
52  {
53  /* Remove the drive entry */
55  ObSystemDeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex-1] =
58  ~(1 << (SymbolicLink->DosDeviceDriveIndex-1));
60 
61  /* Reset the drive index, valid drive index starts from 1 */
62  SymbolicLink->DosDeviceDriveIndex = 0;
63  }
64 
65  ObpDereferenceNameInfo(ObjectNameInfo);
66 }
67 
69 NTAPI
72  IN OUT PUNICODE_STRING TargetPath,
74  OUT PVOID *Object)
75 {
77  BOOLEAN ManualUnlock;
78 
79  if (! TargetPath || ! Object || ! Context || ! Directory ||
80  ! SymbolicLinkDirectory)
81  {
83  }
84 
85  /* FIXME: Need to support Device maps */
86 
87  /* Try walking the target path and open each part of the path */
88  while (TargetPath->Length)
89  {
90  /* Strip '\' if present at the beginning of the target path */
91  if (TargetPath->Length >= sizeof(OBJ_NAME_PATH_SEPARATOR)&&
92  TargetPath->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
93  {
94  TargetPath->Buffer++;
95  TargetPath->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
96  }
97 
98  /* Remember the current component of the target path */
99  Name = *TargetPath;
100 
101  /* Move forward to the next component of the target path */
102  while (TargetPath->Length >= sizeof(OBJ_NAME_PATH_SEPARATOR))
103  {
104  if (TargetPath->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)
105  {
106  TargetPath->Buffer++;
107  TargetPath->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
108  }
109  else
110  break;
111  }
112 
113  Name.Length -= TargetPath->Length;
114 
115  /* Finished processing the entire path, stop */
116  if (! Name.Length)
117  break;
118 
119  /*
120  * Make sure a deadlock does not occur as an exclusive lock on a pushlock
121  * would have already taken one in ObpLookupObjectName() on the parent
122  * directory where the symlink is being created [ObInsertObject()].
123  * Prevent recursive locking by faking lock state in the lookup context
124  * when the current directory is same as the parent directory where
125  * the symlink is being created. If the lock state is not faked,
126  * ObpLookupEntryDirectory() will try to get a recursive lock on the
127  * pushlock and hang. For e.g. this happens when a substed drive is pointed to
128  * another substed drive.
129  */
130  if (*Directory == SymbolicLinkDirectory && ! Context->DirectoryLocked)
131  {
132  /* Fake lock state so that ObpLookupEntryDirectory() doesn't attempt a lock */
133  ManualUnlock = TRUE;
134  Context->DirectoryLocked = TRUE;
135  }
136  else
137  ManualUnlock = FALSE;
138 
139  *Object = ObpLookupEntryDirectory(*Directory,
140  &Name,
141  0,
142  FALSE,
143  Context);
144 
145  /* Locking was faked, undo it now */
146  if (*Directory == SymbolicLinkDirectory && ManualUnlock)
147  Context->DirectoryLocked = FALSE;
148 
149  /* Lookup failed, stop */
150  if (! *Object)
151  break;
152 
153  if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObpDirectoryObjectType)
154  {
155  /* Make this current directory, and continue search */
156  *Directory = (POBJECT_DIRECTORY)*Object;
157  }
158  else if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObpSymbolicLinkObjectType &&
159  (((POBJECT_SYMBOLIC_LINK)*Object)->DosDeviceDriveIndex == 0))
160  {
161  /* Symlink points to another initialized symlink, ask caller to reparse */
162  *Directory = ObpRootDirectoryObject;
163  TargetPath = &((POBJECT_SYMBOLIC_LINK)*Object)->LinkTarget;
164  return STATUS_REPARSE_OBJECT;
165  }
166  else
167  {
168  /* Neither directory or symlink, stop */
169  break;
170  }
171  }
172 
173  /* Return a valid object, only if object type is IoDeviceObject */
174  if (*Object &&
176  {
177  *Object = NULL;
178  }
179  return STATUS_SUCCESS;
180 }
181 
182 VOID
183 NTAPI
185 {
186  POBJECT_HEADER ObjectHeader;
187  POBJECT_HEADER_NAME_INFO ObjectNameInfo;
188  PVOID Object = NULL;
190  UNICODE_STRING TargetPath;
193  ULONG ReparseCnt;
194  const ULONG MaxReparseAttempts = 20;
196 
197  /* FIXME: Need to support Device maps */
198 
199  /* Get header data */
200  ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink);
201  ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
202 
203  /* Check if we are not actually in a directory with a device map */
204  if (!(ObjectNameInfo) ||
205  !(ObjectNameInfo->Directory) /*||
206  !(ObjectNameInfo->Directory->DeviceMap)*/)
207  {
208  ObpDereferenceNameInfo(ObjectNameInfo);
209  return;
210  }
211 
212  /* Check if it's a DOS drive letter, and set the drive index accordingly */
213  if (ObjectNameInfo->Name.Length == 2 * sizeof(WCHAR) &&
214  ObjectNameInfo->Name.Buffer[1] == L':' &&
215  ( (ObjectNameInfo->Name.Buffer[0] >= L'A' &&
216  ObjectNameInfo->Name.Buffer[0] <= L'Z') ||
217  (ObjectNameInfo->Name.Buffer[0] >= L'a' &&
218  ObjectNameInfo->Name.Buffer[0] <= L'z') ))
219  {
220  SymbolicLink->DosDeviceDriveIndex =
221  RtlUpcaseUnicodeChar(ObjectNameInfo->Name.Buffer[0]) - L'A';
222  /* The Drive index start from 1 */
223  SymbolicLink->DosDeviceDriveIndex++;
224 
225  /* Initialize lookup context */
226  ObpInitializeLookupContext(&Context);
227 
228  /* Start the search from the root */
229  Directory = ObpRootDirectoryObject;
230  TargetPath = SymbolicLink->LinkTarget;
231 
232  /*
233  * Locate the IoDeviceObject if any this symbolic link points to.
234  * To prevent endless reparsing, setting an upper limit on the
235  * number of reparses.
236  */
237  Status = STATUS_REPARSE_OBJECT;
238  ReparseCnt = 0;
239  while (Status == STATUS_REPARSE_OBJECT &&
240  ReparseCnt < MaxReparseAttempts)
241  {
242  Status =
244  &Directory,
245  &TargetPath,
246  &Context,
247  &Object);
248  if (Status == STATUS_REPARSE_OBJECT)
249  ReparseCnt++;
250  }
251 
252  /* Cleanup lookup context */
253  ObpReleaseLookupContext(&Context);
254 
255  /* Error, or max resparse attemtps exceeded */
256  if (! NT_SUCCESS(Status) || ReparseCnt >= MaxReparseAttempts)
257  {
258  /* Cleanup */
259  ObpDereferenceNameInfo(ObjectNameInfo);
260  return;
261  }
262 
263  if (Object)
264  {
265  /* Calculate the drive type */
266  switch(((PDEVICE_OBJECT)Object)->DeviceType)
267  {
269  DriveType = DOSDEVICE_DRIVE_RAMDISK;
270  break;
271  case FILE_DEVICE_CD_ROM:
273  DriveType = DOSDEVICE_DRIVE_CDROM;
274  break;
275  case FILE_DEVICE_DISK:
278  if (((PDEVICE_OBJECT)Object)->Characteristics & FILE_REMOVABLE_MEDIA)
279  DriveType = DOSDEVICE_DRIVE_REMOVABLE;
280  else
281  DriveType = DOSDEVICE_DRIVE_FIXED;
282  break;
283  case FILE_DEVICE_NETWORK:
285  DriveType = DOSDEVICE_DRIVE_REMOTE;
286  break;
287  default:
288  DPRINT1("Device Type %lu for %wZ is not known or unhandled\n",
289  ((PDEVICE_OBJECT)Object)->DeviceType,
290  &SymbolicLink->LinkTarget);
291  DriveType = DOSDEVICE_DRIVE_UNKNOWN;
292  }
293  }
294 
295  /* Add a new drive entry */
297  ObSystemDeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex-1] =
298  (UCHAR)DriveType;
300  1 << (SymbolicLink->DosDeviceDriveIndex-1);
302  }
303 
304  /* Cleanup */
305  ObpDereferenceNameInfo(ObjectNameInfo);
306 }
307 
308 /*++
309 * @name ObpDeleteSymbolicLink
310 *
311 * The ObpDeleteSymbolicLink routine <FILLMEIN>
312 *
313 * @param ObjectBody
314 * <FILLMEIN>
315 *
316 * @return None.
317 *
318 * @remarks None.
319 *
320 *--*/
321 VOID
322 NTAPI
324 {
325  POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ObjectBody;
326 
327  /* Make sure that the symbolic link has a name */
328  if (SymlinkObject->LinkTarget.Buffer)
329  {
330  /* Free the name */
331  ExFreePool(SymlinkObject->LinkTarget.Buffer);
332  SymlinkObject->LinkTarget.Buffer = NULL;
333  }
334 }
335 
336 /*++
337 * @name ObpParseSymbolicLink
338 *
339 * The ObpParseSymbolicLink routine <FILLMEIN>
340 *
341 * @param Object
342 * <FILLMEIN>
343 *
344 * @param NextObject
345 * <FILLMEIN>
346 *
347 * @param FullPath
348 * <FILLMEIN>
349 *
350 * @param RemainingPath
351 * <FILLMEIN>
352 *
353 * @param Attributes
354 * <FILLMEIN>
355 *
356 * @return STATUS_SUCCESS or appropriate error value.
357 *
358 * @remarks None.
359 *
360 *--*/
361 NTSTATUS
362 NTAPI
368  IN OUT PUNICODE_STRING FullPath,
371  IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
372  OUT PVOID *NextObject)
373 {
374  POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ParsedObject;
375  PUNICODE_STRING TargetPath;
376  PWSTR NewTargetPath;
377  ULONG LengthUsed, MaximumLength, TempLength;
379  PAGED_CODE();
380 
381  /* Assume failure */
382  *NextObject = NULL;
383 
384  /* Check if we're out of name to parse */
385  if (!RemainingName->Length)
386  {
387  /* Check if we got an object type */
388  if (ObjectType)
389  {
390  /* Reference the object only */
391  Status = ObReferenceObjectByPointer(ParsedObject,
392  0,
393  ObjectType,
394  AccessMode);
395  if (NT_SUCCESS(Status))
396  {
397  /* Return it */
398  *NextObject = ParsedObject;
399  }
400 
401  if ((NT_SUCCESS(Status)) || (Status != STATUS_OBJECT_TYPE_MISMATCH))
402  {
403  /* Fail */
404  return Status;
405  }
406  }
407  }
408  else if (RemainingName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)
409  {
410  /* Symbolic links must start with a backslash */
412  }
413 
414  /* Check if this symlink is bound to a specific object */
415  if (SymlinkObject->LinkTargetObject)
416  {
418  }
419 
420  /* Set the target path and length */
421  TargetPath = &SymlinkObject->LinkTarget;
422  TempLength = TargetPath->Length;
423 
424  /*
425  * Strip off the extra trailing '\', if we don't do this we will end up
426  * adding a extra '\' between TargetPath and RemainingName
427  * causing caller's like ObpLookupObjectName() to fail.
428  */
429  if (TempLength && RemainingName->Length)
430  {
431  /* The target and remaining names aren't empty, so check for slashes */
432  if ((TargetPath->Buffer[TempLength / sizeof(WCHAR) - 1] ==
434  (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
435  {
436  /* Reduce the length by one to cut off the extra '\' */
437  TempLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
438  }
439  }
440 
441  /* Calculate the new length */
442  LengthUsed = TempLength + RemainingName->Length;
443 
444  /* Check if it's not too much */
445  if (LengthUsed > 0xFFF0)
446  return STATUS_NAME_TOO_LONG;
447 
448  /* Optimization: check if the new name is shorter */
449  if (FullPath->MaximumLength <= LengthUsed)
450  {
451  /* It's not, allocate a new one */
452  MaximumLength = LengthUsed + sizeof(WCHAR);
453  NewTargetPath = ExAllocatePoolWithTag(NonPagedPool,
454  MaximumLength,
455  OB_NAME_TAG);
456  if (!NewTargetPath) return STATUS_INSUFFICIENT_RESOURCES;
457  }
458  else
459  {
460  /* It is! Reuse the name... */
461  MaximumLength = FullPath->MaximumLength;
462  NewTargetPath = FullPath->Buffer;
463  }
464 
465  /* Make sure we have a length */
466  if (RemainingName->Length)
467  {
468  /* Copy the new path */
469  RtlMoveMemory((PVOID)((ULONG_PTR)NewTargetPath + TempLength),
470  RemainingName->Buffer,
471  RemainingName->Length);
472  }
473 
474  /* Copy the target path and null-terminate it */
475  RtlCopyMemory(NewTargetPath, TargetPath->Buffer, TempLength);
476  NewTargetPath[LengthUsed / sizeof(WCHAR)] = UNICODE_NULL;
477 
478  /* If the optimization didn't work, free the old buffer */
479  if (NewTargetPath != FullPath->Buffer) ExFreePool(FullPath->Buffer);
480 
481  /* Update the path values */
482  FullPath->Length = (USHORT)LengthUsed;
483  FullPath->MaximumLength = (USHORT)MaximumLength;
484  FullPath->Buffer = NewTargetPath;
485 
486  /* Tell the parse routine to start reparsing */
487  return STATUS_REPARSE;
488 }
489 
490 /* PUBLIC FUNCTIONS **********************************************************/
491 
492 /*++
493 * @name NtCreateSymbolicLinkObject
494 * @implemented NT4
495 *
496 * The NtCreateSymbolicLinkObject opens or creates a symbolic link object.
497 *
498 * @param LinkHandle
499 * Variable which receives the symlink handle.
500 *
501 * @param DesiredAccess
502 * Desired access to the symlink.
503 *
504 * @param ObjectAttributes
505 * Structure describing the symlink.
506 *
507 * @param LinkTarget
508 * Unicode string defining the symlink's target
509 *
510 * @return STATUS_SUCCESS or appropriate error value.
511 *
512 * @remarks None.
513 *
514 *--*/
515 NTSTATUS
516 NTAPI
521 {
522  HANDLE hLink;
524  UNICODE_STRING CapturedLinkTarget;
527  PAGED_CODE();
528 
529  /* Check if we need to probe parameters */
530  if (PreviousMode != KernelMode)
531  {
532  _SEH2_TRY
533  {
534  /* Probe the target */
535  CapturedLinkTarget = ProbeForReadUnicodeString(LinkTarget);
536  ProbeForRead(CapturedLinkTarget.Buffer,
537  CapturedLinkTarget.MaximumLength,
538  sizeof(WCHAR));
539 
540  /* Probe the return handle */
541  ProbeForWriteHandle(LinkHandle);
542  }
544  {
545  /* Return the exception code */
547  }
548  _SEH2_END;
549  }
550  else
551  {
552  /* No need to capture */
553  CapturedLinkTarget = *LinkTarget;
554  }
555 
556  /* Check if the maximum length is odd */
557  if (CapturedLinkTarget.MaximumLength % sizeof(WCHAR))
558  {
559  /* Round it down */
560  CapturedLinkTarget.MaximumLength =
561  (USHORT)ALIGN_DOWN(CapturedLinkTarget.MaximumLength, WCHAR);
562  }
563 
564  /* Fail if the length is odd, or if the maximum is smaller or 0 */
565  if ((CapturedLinkTarget.Length % sizeof(WCHAR)) ||
566  (CapturedLinkTarget.MaximumLength < CapturedLinkTarget.Length) ||
567  !(CapturedLinkTarget.MaximumLength))
568  {
569  /* This message is displayed on the debugger in Windows */
570  DbgPrint("OB: Invalid symbolic link target - %wZ\n",
571  &CapturedLinkTarget);
573  }
574 
575  /* Create the object */
576  Status = ObCreateObject(PreviousMode,
577  ObpSymbolicLinkObjectType,
578  ObjectAttributes,
579  PreviousMode,
580  NULL,
581  sizeof(OBJECT_SYMBOLIC_LINK),
582  0,
583  0,
584  (PVOID*)&SymbolicLink);
585  if (NT_SUCCESS(Status))
586  {
587  /* Success! Fill in the creation time immediately */
588  KeQuerySystemTime(&SymbolicLink->CreationTime);
589 
590  /* Setup the target name */
591  SymbolicLink->LinkTarget.Length = CapturedLinkTarget.Length;
592  SymbolicLink->LinkTarget.MaximumLength = CapturedLinkTarget.MaximumLength;
593  SymbolicLink->LinkTarget.Buffer =
595  CapturedLinkTarget.MaximumLength,
597  if (!SymbolicLink->LinkTarget.Buffer)
598  {
599  /* Dereference the symbolic link object and fail */
600  ObDereferenceObject(SymbolicLink);
601  return STATUS_NO_MEMORY;
602  }
603 
604  /* Copy it */
605  _SEH2_TRY
606  {
607  RtlCopyMemory(SymbolicLink->LinkTarget.Buffer,
608  CapturedLinkTarget.Buffer,
609  CapturedLinkTarget.MaximumLength);
610  }
612  {
613  ObDereferenceObject(SymbolicLink);
615  }
616  _SEH2_END;
617 
618  /* Initialize the remaining name, dos drive index and target object */
619  SymbolicLink->LinkTargetObject = NULL;
620  SymbolicLink->DosDeviceDriveIndex = 0;
622 
623  /* Insert it into the object tree */
624  Status = ObInsertObject(SymbolicLink,
625  NULL,
626  DesiredAccess,
627  0,
628  NULL,
629  &hLink);
630  if (NT_SUCCESS(Status))
631  {
632  _SEH2_TRY
633  {
634  /* Return the handle to caller */
635  *LinkHandle = hLink;
636  }
638  {
639  /* Get exception code */
640  Status = _SEH2_GetExceptionCode();
641  }
642  _SEH2_END;
643  }
644  }
645 
646  /* Return status to caller */
647  return Status;
648 }
649 
650 /*++
651 * @name NtOpenSymbolicLinkObject
652 * @implemented NT4
653 *
654 * The NtOpenSymbolicLinkObject opens a symbolic link object.
655 *
656 * @param LinkHandle
657 * Variable which receives the symlink handle.
658 *
659 * @param DesiredAccess
660 * Desired access to the symlink.
661 *
662 * @param ObjectAttributes
663 * Structure describing the symlink.
664 *
665 * @return STATUS_SUCCESS or appropriate error value.
666 *
667 * @remarks None.
668 *
669 *--*/
670 NTSTATUS
671 NTAPI
675 {
676  HANDLE hLink;
679  PAGED_CODE();
680 
681  /* Check if we need to probe parameters */
682  if (PreviousMode != KernelMode)
683  {
684  _SEH2_TRY
685  {
686  /* Probe the return handle */
687  ProbeForWriteHandle(LinkHandle);
688  }
690  {
691  /* Return the exception code */
693  }
694  _SEH2_END;
695  }
696 
697  /* Open the object */
698  Status = ObOpenObjectByName(ObjectAttributes,
699  ObpSymbolicLinkObjectType,
700  PreviousMode,
701  NULL,
702  DesiredAccess,
703  NULL,
704  &hLink);
705 
706  _SEH2_TRY
707  {
708  /* Return the handle to caller */
709  *LinkHandle = hLink;
710  }
712  {
713  /* Get exception code */
714  Status = _SEH2_GetExceptionCode();
715  }
716  _SEH2_END;
717 
718  /* Return status to caller */
719  return Status;
720 }
721 
722 /*++
723 * @name NtQuerySymbolicLinkObject
724 * @implemented NT4
725 *
726 * The NtQuerySymbolicLinkObject queries a symbolic link object.
727 *
728 * @param LinkHandle
729 * Symlink handle to query
730 *
731 * @param LinkTarget
732 * Unicode string defining the symlink's target
733 *
734 * @param ResultLength
735 * Caller supplied storage for the number of bytes written (or NULL).
736 *
737 * @return STATUS_SUCCESS or appropriate error value.
738 *
739 * @remarks None.
740 *
741 *--*/
742 NTSTATUS
743 NTAPI
747 {
748  UNICODE_STRING SafeLinkTarget = { 0, 0, NULL };
749  POBJECT_SYMBOLIC_LINK SymlinkObject;
752  ULONG LengthUsed;
753  PAGED_CODE();
754 
755  if (PreviousMode != KernelMode)
756  {
757  _SEH2_TRY
758  {
759  /* Probe the unicode string for read and write */
760  ProbeForWriteUnicodeString(LinkTarget);
761 
762  /* Probe the unicode string's buffer for write */
763  SafeLinkTarget = *LinkTarget;
764  ProbeForWrite(SafeLinkTarget.Buffer,
765  SafeLinkTarget.MaximumLength,
766  sizeof(WCHAR));
767 
768  /* Probe the return length */
770  }
772  {
773  /* Return the exception code */
775  }
776  _SEH2_END;
777  }
778  else
779  {
780  /* No need to probe */
781  SafeLinkTarget = *LinkTarget;
782  }
783 
784  /* Reference the object */
785  Status = ObReferenceObjectByHandle(LinkHandle,
787  ObpSymbolicLinkObjectType,
788  PreviousMode,
789  (PVOID *)&SymlinkObject,
790  NULL);
791  if (NT_SUCCESS(Status))
792  {
793  /* Lock the object */
795 
796  /*
797  * So here's the thing: If you specify a return length, then the
798  * implementation will use the maximum length. If you don't, then
799  * it will use the length.
800  */
801  LengthUsed = ResultLength ? SymlinkObject->LinkTarget.MaximumLength :
802  SymlinkObject->LinkTarget.Length;
803 
804  /* Enter SEH so we can safely copy */
805  _SEH2_TRY
806  {
807  /* Make sure our buffer will fit */
808  if (LengthUsed <= SafeLinkTarget.MaximumLength)
809  {
810  /* Copy the buffer */
811  RtlCopyMemory(SafeLinkTarget.Buffer,
812  SymlinkObject->LinkTarget.Buffer,
813  LengthUsed);
814 
815  /* Copy the new length */
816  LinkTarget->Length = SymlinkObject->LinkTarget.Length;
817  }
818  else
819  {
820  /* Otherwise set the failure status */
821  Status = STATUS_BUFFER_TOO_SMALL;
822  }
823 
824  /* In both cases, check if the required length was requested */
825  if (ResultLength)
826  {
827  /* Then return it */
828  *ResultLength = SymlinkObject->LinkTarget.MaximumLength;
829  }
830  }
832  {
833  /* Get the error code */
834  Status = _SEH2_GetExceptionCode();
835  }
836  _SEH2_END;
837 
838  /* Unlock and dereference the object */
840  ObDereferenceObject(SymlinkObject);
841  }
842 
843  /* Return query status */
844  return Status;
845 }
846 
847 /* 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:2523
DWORD *typedef PVOID
Definition: winlogon.h:61
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
struct _OBJECT_DIRECTORY * POBJECT_DIRECTORY
#define FILE_DEVICE_NETWORK
Definition: winioctl.h:123
#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
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
__wchar_t WCHAR
Definition: xmlstorage.h:180
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
#define DOSDEVICE_DRIVE_CDROM
Definition: obtypes.h:168
UNICODE_STRING Name
Definition: obtypes.h:433
PVOID *typedef PWSTR
Definition: winlogon.h:66
UINT DriveType
KPROCESSOR_MODE NTAPI ExGetPreviousMode(VOID)
Definition: sysinfo.c:2927
#define FILE_DEVICE_VIRTUAL_DISK
Definition: winioctl.h:141
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
#define WCHAR
Definition: msvc.h:43
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:52
_SEH2_TRY
Definition: create.c:4250
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
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
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:27
#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 EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
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:938
#define FILE_DEVICE_DISK_FILE_SYSTEM
Definition: winioctl.h:113
unsigned char BOOLEAN
_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
LONG NTSTATUS
Definition: precomp.h:26
#define DOSDEVICE_DRIVE_FIXED
Definition: obtypes.h:166
#define _SEH2_YIELD(STMT_)
Definition: pseh2_64.h:8
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
#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
_In_ PUNICODE_STRING Name
Definition: mrx.h:218
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:1087
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:123
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:414
PDEVICE_MAP ObSystemDeviceMap
Definition: obinit.c:46
Status
Definition: gdiplustypes.h:24
FORCEINLINE VOID ObpReleaseLookupContext(IN POBP_LOOKUP_CONTEXT Context)
Definition: ob_x.h:255
UnicodeString MaximumLength
Definition: rtlfuncs.h:2982
DWORD *typedef HANDLE
Definition: winlogon.h:61
_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:2926
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
struct tagContext Context
Definition: acpixf.h:1014
unsigned int ULONG
Definition: retypes.h:1
#define SYMBOLIC_LINK_QUERY
Definition: nt_native.h:1265
base for all directory entries
Definition: entries.h:138
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define UNIMPLEMENTED
Definition: debug.h:114
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
KGUARDED_MUTEX ObpDeviceMapLock
Definition: oblife.c:24
_In_ BOOLEAN _In_ USHORT Directory
Definition: rtlfuncs.h:3718
return STATUS_SUCCESS
Definition: btrfs.c:2710
FORCEINLINE VOID ObpDereferenceNameInfo(IN POBJECT_HEADER_NAME_INFO HeaderNameInfo)
Definition: ob_x.h:143
POBJECT_TYPE IoDeviceObjectType
Definition: iomgr.c:35
IN HDEVINFO IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
Definition: devinst.c:44
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
struct _ACPI_EFI_FILE_HANDLE CHAR16 UINT64 UINT64 Attributes
Definition: acefiex.h:335
_Inout_ PFCB _Inout_ PUNICODE_STRING RemainingName
Definition: cdprocs.h:806