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>
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, ObInitSymbolicLinkImplementation)
22 /* GLOBALS ******************************************************************/
24 POBJECT_TYPE ObSymbolicLinkType
= NULL
;
26 static GENERIC_MAPPING ObpSymbolicLinkMapping
= {
27 STANDARD_RIGHTS_READ
|SYMBOLIC_LINK_QUERY
,
28 STANDARD_RIGHTS_WRITE
,
29 STANDARD_RIGHTS_EXECUTE
|SYMBOLIC_LINK_QUERY
,
30 SYMBOLIC_LINK_ALL_ACCESS
};
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
139 ObInitSymbolicLinkImplementation (VOID
)
142 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
144 DPRINT("Creating SymLink Object Type\n");
146 /* Initialize the Directory type */
147 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
148 RtlInitUnicodeString(&Name
, L
"SymbolicLink");
149 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
150 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(SYMLINK_OBJECT
);
151 ObjectTypeInitializer
.GenericMapping
= ObpSymbolicLinkMapping
;
152 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
153 ObjectTypeInitializer
.ValidAccessMask
= SYMBOLIC_LINK_ALL_ACCESS
;
154 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
155 ObjectTypeInitializer
.ParseProcedure
= (OB_PARSE_METHOD
)ObpParseSymbolicLink
;
156 ObjectTypeInitializer
.DeleteProcedure
= ObpDeleteSymbolicLink
;
157 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ObSymbolicLinkType
);
161 /**********************************************************************
163 * NtCreateSymbolicLinkObject
175 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle
,
176 IN ACCESS_MASK DesiredAccess
,
177 IN POBJECT_ATTRIBUTES ObjectAttributes
,
178 IN PUNICODE_STRING LinkTarget
)
181 PSYMLINK_OBJECT SymbolicLink
;
182 UNICODE_STRING CapturedLinkTarget
;
183 KPROCESSOR_MODE PreviousMode
;
184 NTSTATUS Status
= STATUS_SUCCESS
;
188 PreviousMode
= ExGetPreviousMode();
190 if(PreviousMode
!= KernelMode
)
194 ProbeForWriteHandle(LinkHandle
);
198 Status
= _SEH_GetExceptionCode();
202 if(!NT_SUCCESS(Status
))
208 Status
= ProbeAndCaptureUnicodeString(&CapturedLinkTarget
,
211 if(!NT_SUCCESS(Status
))
213 DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
217 DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, LinkTarget %wZ)\n",
221 &CapturedLinkTarget
);
223 Status
= ObCreateObject(ExGetPreviousMode(),
228 sizeof(SYMLINK_OBJECT
),
231 (PVOID
*)&SymbolicLink
);
232 if (NT_SUCCESS(Status
))
234 SymbolicLink
->TargetName
.Length
= 0;
235 SymbolicLink
->TargetName
.MaximumLength
=
236 CapturedLinkTarget
.Length
+ sizeof(WCHAR
);
237 SymbolicLink
->TargetName
.Buffer
=
238 ExAllocatePoolWithTag(NonPagedPool
,
239 SymbolicLink
->TargetName
.MaximumLength
,
241 RtlCopyUnicodeString(&SymbolicLink
->TargetName
,
242 &CapturedLinkTarget
);
244 DPRINT("DeviceName %S\n", SymbolicLink
->TargetName
.Buffer
);
246 ZwQuerySystemTime (&SymbolicLink
->CreateTime
);
248 Status
= ObInsertObject ((PVOID
)SymbolicLink
,
254 if (NT_SUCCESS(Status
))
262 Status
= _SEH_GetExceptionCode();
266 ObDereferenceObject(SymbolicLink
);
269 ReleaseCapturedUnicodeString(&CapturedLinkTarget
,
276 /**********************************************************************
278 * NtOpenSymbolicLinkObject
290 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle
,
291 IN ACCESS_MASK DesiredAccess
,
292 IN POBJECT_ATTRIBUTES ObjectAttributes
)
295 KPROCESSOR_MODE PreviousMode
;
296 NTSTATUS Status
= STATUS_SUCCESS
;
300 PreviousMode
= ExGetPreviousMode();
302 if(PreviousMode
!= KernelMode
)
306 ProbeForWriteHandle(LinkHandle
);
310 Status
= _SEH_GetExceptionCode();
314 if(!NT_SUCCESS(Status
))
320 DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
321 ObjectAttributes
->ObjectName
);
323 Status
= ObOpenObjectByName(ObjectAttributes
,
330 if(NT_SUCCESS(Status
))
338 Status
= _SEH_GetExceptionCode();
347 /**********************************************************************
349 * NtQuerySymbolicLinkObject
361 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle
,
362 OUT PUNICODE_STRING LinkTarget
,
363 OUT PULONG ResultLength OPTIONAL
)
365 UNICODE_STRING SafeLinkTarget
;
366 PSYMLINK_OBJECT SymlinkObject
;
367 KPROCESSOR_MODE PreviousMode
;
368 NTSTATUS Status
= STATUS_SUCCESS
;
372 PreviousMode
= ExGetPreviousMode();
374 if(PreviousMode
!= KernelMode
)
378 /* probe the unicode string and buffers supplied */
379 ProbeForWrite(LinkTarget
,
380 sizeof(UNICODE_STRING
),
382 SafeLinkTarget
= *LinkTarget
;
383 ProbeForWrite(SafeLinkTarget
.Buffer
,
384 SafeLinkTarget
.MaximumLength
,
387 if(ResultLength
!= NULL
)
389 ProbeForWriteUlong(ResultLength
);
394 Status
= _SEH_GetExceptionCode();
398 if(!NT_SUCCESS(Status
))
405 SafeLinkTarget
= *LinkTarget
;
408 Status
= ObReferenceObjectByHandle(LinkHandle
,
412 (PVOID
*)&SymlinkObject
,
414 if (NT_SUCCESS(Status
))
416 ULONG LengthRequired
= SymlinkObject
->TargetName
.Length
+ sizeof(WCHAR
);
420 if(SafeLinkTarget
.MaximumLength
>= LengthRequired
)
422 /* don't pass TargetLink to RtlCopyUnicodeString here because the caller
423 might have modified the structure which could lead to a copy into
425 RtlCopyUnicodeString(&SafeLinkTarget
,
426 &SymlinkObject
->TargetName
);
427 SafeLinkTarget
.Buffer
[SafeLinkTarget
.Length
/ sizeof(WCHAR
)] = L
'\0';
428 /* copy back the new UNICODE_STRING structure */
429 *LinkTarget
= SafeLinkTarget
;
433 Status
= STATUS_BUFFER_TOO_SMALL
;
436 if(ResultLength
!= NULL
)
438 *ResultLength
= LengthRequired
;
443 Status
= _SEH_GetExceptionCode();
447 ObDereferenceObject(SymlinkObject
);