3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/symlink.c
6 * PURPOSE: Implements symbolic links
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
18 /* GLOBALS ******************************************************************/
20 POBJECT_TYPE ObSymbolicLinkType
= NULL
;
22 static GENERIC_MAPPING ObpSymbolicLinkMapping
= {
23 STANDARD_RIGHTS_READ
|SYMBOLIC_LINK_QUERY
,
24 STANDARD_RIGHTS_WRITE
,
25 STANDARD_RIGHTS_EXECUTE
|SYMBOLIC_LINK_QUERY
,
26 SYMBOLIC_LINK_ALL_ACCESS
};
28 #define TAG_SYMLINK_TTARGET TAG('S', 'Y', 'T', 'T')
29 #define TAG_SYMLINK_TARGET TAG('S', 'Y', 'M', 'T')
32 /* FUNCTIONS ****************************************************************/
34 /**********************************************************************
36 * ObpDeleteSymbolicLink
48 ObpDeleteSymbolicLink(PVOID ObjectBody
)
50 PSYMLINK_OBJECT SymlinkObject
= (PSYMLINK_OBJECT
)ObjectBody
;
52 ExFreePool(SymlinkObject
->TargetName
.Buffer
);
56 /**********************************************************************
58 * ObpParseSymbolicLink
69 ObpParseSymbolicLink(PVOID Object
,
71 PUNICODE_STRING FullPath
,
72 PWSTR
* RemainingPath
,
75 PSYMLINK_OBJECT SymlinkObject
= (PSYMLINK_OBJECT
) Object
;
76 UNICODE_STRING TargetPath
;
78 DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath
);
81 * Stop parsing if the entire path has been parsed and
82 * the desired object is a symbolic link object.
84 if (((*RemainingPath
== NULL
) || (**RemainingPath
== 0)) &&
85 (Attributes
& OBJ_OPENLINK
))
87 DPRINT("Parsing stopped!\n");
89 return(STATUS_SUCCESS
);
92 /* build the expanded path */
93 TargetPath
.MaximumLength
= SymlinkObject
->TargetName
.Length
+ sizeof(WCHAR
);
94 if (RemainingPath
&& *RemainingPath
)
96 TargetPath
.MaximumLength
+= (wcslen(*RemainingPath
) * sizeof(WCHAR
));
98 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
99 TargetPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
100 TargetPath
.MaximumLength
,
101 TAG_SYMLINK_TTARGET
);
102 wcscpy(TargetPath
.Buffer
, SymlinkObject
->TargetName
.Buffer
);
103 if (RemainingPath
&& *RemainingPath
)
105 wcscat(TargetPath
.Buffer
, *RemainingPath
);
108 /* transfer target path buffer into FullPath */
109 ExFreePool(FullPath
->Buffer
);
110 FullPath
->Length
= TargetPath
.Length
;
111 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
112 FullPath
->Buffer
= TargetPath
.Buffer
;
114 /* reinitialize RemainingPath for reparsing */
115 *RemainingPath
= FullPath
->Buffer
;
118 return STATUS_REPARSE
;
122 /**********************************************************************
124 * ObInitSymbolicLinkImplementation
138 ObInitSymbolicLinkImplementation (VOID
)
141 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
143 DPRINT1("Creating SymLink Object Type\n");
145 /* Initialize the Directory type */
146 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
147 RtlInitUnicodeString(&Name
, L
"SymbolicLink");
148 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
149 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(SYMLINK_OBJECT
);
150 ObjectTypeInitializer
.GenericMapping
= ObpSymbolicLinkMapping
;
151 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
152 ObjectTypeInitializer
.ValidAccessMask
= SYMBOLIC_LINK_ALL_ACCESS
;
153 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
154 ObjectTypeInitializer
.ParseProcedure
= ObpParseSymbolicLink
;
155 ObjectTypeInitializer
.DeleteProcedure
= ObpDeleteSymbolicLink
;
156 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ObSymbolicLinkType
);
160 /**********************************************************************
162 * NtCreateSymbolicLinkObject
174 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle
,
175 IN ACCESS_MASK DesiredAccess
,
176 IN POBJECT_ATTRIBUTES ObjectAttributes
,
177 IN PUNICODE_STRING LinkTarget
)
180 PSYMLINK_OBJECT SymbolicLink
;
181 UNICODE_STRING CapturedLinkTarget
;
182 KPROCESSOR_MODE PreviousMode
;
183 NTSTATUS Status
= STATUS_SUCCESS
;
187 PreviousMode
= ExGetPreviousMode();
189 if(PreviousMode
!= KernelMode
)
193 ProbeForWrite(LinkHandle
,
199 Status
= _SEH_GetExceptionCode();
203 if(!NT_SUCCESS(Status
))
209 Status
= RtlCaptureUnicodeString(&CapturedLinkTarget
,
214 if(!NT_SUCCESS(Status
))
216 DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
220 DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, LinkTarget %wZ)\n",
224 &CapturedLinkTarget
);
226 Status
= ObCreateObject(ExGetPreviousMode(),
231 sizeof(SYMLINK_OBJECT
),
234 (PVOID
*)&SymbolicLink
);
235 if (NT_SUCCESS(Status
))
237 SymbolicLink
->TargetName
.Length
= 0;
238 SymbolicLink
->TargetName
.MaximumLength
=
239 ((wcslen(LinkTarget
->Buffer
) + 1) * sizeof(WCHAR
));
240 SymbolicLink
->TargetName
.Buffer
=
241 ExAllocatePoolWithTag(NonPagedPool
,
242 SymbolicLink
->TargetName
.MaximumLength
,
244 RtlCopyUnicodeString(&SymbolicLink
->TargetName
,
245 &CapturedLinkTarget
);
247 DPRINT("DeviceName %S\n", SymbolicLink
->TargetName
.Buffer
);
249 ZwQuerySystemTime (&SymbolicLink
->CreateTime
);
251 Status
= ObInsertObject ((PVOID
)SymbolicLink
,
257 if (NT_SUCCESS(Status
))
265 Status
= _SEH_GetExceptionCode();
269 ObDereferenceObject(SymbolicLink
);
272 RtlReleaseCapturedUnicodeString(&CapturedLinkTarget
,
280 /**********************************************************************
282 * NtOpenSymbolicLinkObject
294 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle
,
295 IN ACCESS_MASK DesiredAccess
,
296 IN POBJECT_ATTRIBUTES ObjectAttributes
)
299 KPROCESSOR_MODE PreviousMode
;
300 NTSTATUS Status
= STATUS_SUCCESS
;
304 PreviousMode
= ExGetPreviousMode();
306 if(PreviousMode
!= KernelMode
)
310 ProbeForWrite(LinkHandle
,
316 Status
= _SEH_GetExceptionCode();
320 if(!NT_SUCCESS(Status
))
326 DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
327 ObjectAttributes
->ObjectName
);
329 Status
= ObOpenObjectByName(ObjectAttributes
,
336 if(NT_SUCCESS(Status
))
344 Status
= _SEH_GetExceptionCode();
353 /**********************************************************************
355 * NtQuerySymbolicLinkObject
367 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle
,
368 OUT PUNICODE_STRING LinkTarget
,
369 OUT PULONG ResultLength OPTIONAL
)
371 UNICODE_STRING SafeLinkTarget
;
372 PSYMLINK_OBJECT SymlinkObject
;
373 KPROCESSOR_MODE PreviousMode
;
374 NTSTATUS Status
= STATUS_SUCCESS
;
378 PreviousMode
= ExGetPreviousMode();
380 if(PreviousMode
!= KernelMode
)
384 /* probe the unicode string and buffers supplied */
385 ProbeForWrite(LinkTarget
,
386 sizeof(UNICODE_STRING
),
388 SafeLinkTarget
= *LinkTarget
;
389 ProbeForWrite(SafeLinkTarget
.Buffer
,
390 SafeLinkTarget
.MaximumLength
,
393 if(ResultLength
!= NULL
)
395 ProbeForWrite(ResultLength
,
402 Status
= _SEH_GetExceptionCode();
406 if(!NT_SUCCESS(Status
))
413 SafeLinkTarget
= *LinkTarget
;
416 Status
= ObReferenceObjectByHandle(LinkHandle
,
420 (PVOID
*)&SymlinkObject
,
422 if (NT_SUCCESS(Status
))
424 ULONG LengthRequired
= SymlinkObject
->TargetName
.Length
+ sizeof(WCHAR
);
428 if(SafeLinkTarget
.MaximumLength
>= LengthRequired
)
430 /* don't pass TargetLink to RtlCopyUnicodeString here because the caller
431 might have modified the structure which could lead to a copy into
433 RtlCopyUnicodeString(&SafeLinkTarget
,
434 &SymlinkObject
->TargetName
);
435 SafeLinkTarget
.Buffer
[SafeLinkTarget
.Length
/ sizeof(WCHAR
)] = L
'\0';
436 /* copy back the new UNICODE_STRING structure */
437 *LinkTarget
= SafeLinkTarget
;
441 Status
= STATUS_BUFFER_TOO_SMALL
;
444 if(ResultLength
!= NULL
)
446 *ResultLength
= LengthRequired
;
451 Status
= _SEH_GetExceptionCode();
455 ObDereferenceObject(SymlinkObject
);