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 /* FUNCTIONS ****************************************************************/
30 /**********************************************************************
32 * ObpDeleteSymbolicLink
44 ObpDeleteSymbolicLink(PVOID ObjectBody
)
46 PSYMLINK_OBJECT SymlinkObject
= (PSYMLINK_OBJECT
)ObjectBody
;
48 ExFreePool(SymlinkObject
->TargetName
.Buffer
);
52 /**********************************************************************
54 * ObpParseSymbolicLink
65 ObpParseSymbolicLink(PVOID Object
,
67 PUNICODE_STRING FullPath
,
68 PWSTR
* RemainingPath
,
71 PSYMLINK_OBJECT SymlinkObject
= (PSYMLINK_OBJECT
) Object
;
72 UNICODE_STRING TargetPath
;
74 DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath
);
77 * Stop parsing if the entire path has been parsed and
78 * the desired object is a symbolic link object.
80 if (((*RemainingPath
== NULL
) || (**RemainingPath
== 0)) &&
81 (Attributes
& OBJ_OPENLINK
))
83 DPRINT("Parsing stopped!\n");
85 return(STATUS_SUCCESS
);
88 /* build the expanded path */
89 TargetPath
.MaximumLength
= SymlinkObject
->TargetName
.Length
+ sizeof(WCHAR
);
90 if (RemainingPath
&& *RemainingPath
)
92 TargetPath
.MaximumLength
+= (wcslen(*RemainingPath
) * sizeof(WCHAR
));
94 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
95 TargetPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
96 TargetPath
.MaximumLength
,
98 wcscpy(TargetPath
.Buffer
, SymlinkObject
->TargetName
.Buffer
);
99 if (RemainingPath
&& *RemainingPath
)
101 wcscat(TargetPath
.Buffer
, *RemainingPath
);
104 /* transfer target path buffer into FullPath */
105 ExFreePool(FullPath
->Buffer
);
106 FullPath
->Length
= TargetPath
.Length
;
107 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
108 FullPath
->Buffer
= TargetPath
.Buffer
;
110 /* reinitialize RemainingPath for reparsing */
111 *RemainingPath
= FullPath
->Buffer
;
114 return STATUS_REPARSE
;
118 /**********************************************************************
120 * ObInitSymbolicLinkImplementation
135 ObInitSymbolicLinkImplementation (VOID
)
138 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
140 DPRINT("Creating SymLink Object Type\n");
142 /* Initialize the Directory type */
143 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
144 RtlInitUnicodeString(&Name
, L
"SymbolicLink");
145 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
146 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(SYMLINK_OBJECT
);
147 ObjectTypeInitializer
.GenericMapping
= ObpSymbolicLinkMapping
;
148 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
149 ObjectTypeInitializer
.ValidAccessMask
= SYMBOLIC_LINK_ALL_ACCESS
;
150 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
151 ObjectTypeInitializer
.ParseProcedure
= ObpParseSymbolicLink
;
152 ObjectTypeInitializer
.DeleteProcedure
= ObpDeleteSymbolicLink
;
153 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ObSymbolicLinkType
);
157 /**********************************************************************
159 * NtCreateSymbolicLinkObject
171 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle
,
172 IN ACCESS_MASK DesiredAccess
,
173 IN POBJECT_ATTRIBUTES ObjectAttributes
,
174 IN PUNICODE_STRING LinkTarget
)
177 PSYMLINK_OBJECT SymbolicLink
;
178 UNICODE_STRING CapturedLinkTarget
;
179 KPROCESSOR_MODE PreviousMode
;
180 NTSTATUS Status
= STATUS_SUCCESS
;
184 PreviousMode
= ExGetPreviousMode();
186 if(PreviousMode
!= KernelMode
)
190 ProbeForWriteHandle(LinkHandle
);
194 Status
= _SEH_GetExceptionCode();
198 if(!NT_SUCCESS(Status
))
204 Status
= ProbeAndCaptureUnicodeString(&CapturedLinkTarget
,
207 if(!NT_SUCCESS(Status
))
209 DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
213 DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, LinkTarget %wZ)\n",
217 &CapturedLinkTarget
);
219 Status
= ObCreateObject(ExGetPreviousMode(),
224 sizeof(SYMLINK_OBJECT
),
227 (PVOID
*)&SymbolicLink
);
228 if (NT_SUCCESS(Status
))
230 SymbolicLink
->TargetName
.Length
= 0;
231 SymbolicLink
->TargetName
.MaximumLength
=
232 ((wcslen(LinkTarget
->Buffer
) + 1) * sizeof(WCHAR
));
233 SymbolicLink
->TargetName
.Buffer
=
234 ExAllocatePoolWithTag(NonPagedPool
,
235 SymbolicLink
->TargetName
.MaximumLength
,
237 RtlCopyUnicodeString(&SymbolicLink
->TargetName
,
238 &CapturedLinkTarget
);
240 DPRINT("DeviceName %S\n", SymbolicLink
->TargetName
.Buffer
);
242 ZwQuerySystemTime (&SymbolicLink
->CreateTime
);
244 Status
= ObInsertObject ((PVOID
)SymbolicLink
,
250 if (NT_SUCCESS(Status
))
258 Status
= _SEH_GetExceptionCode();
262 ObDereferenceObject(SymbolicLink
);
265 ReleaseCapturedUnicodeString(&CapturedLinkTarget
,
272 /**********************************************************************
274 * NtOpenSymbolicLinkObject
286 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle
,
287 IN ACCESS_MASK DesiredAccess
,
288 IN POBJECT_ATTRIBUTES ObjectAttributes
)
291 KPROCESSOR_MODE PreviousMode
;
292 NTSTATUS Status
= STATUS_SUCCESS
;
296 PreviousMode
= ExGetPreviousMode();
298 if(PreviousMode
!= KernelMode
)
302 ProbeForWriteHandle(LinkHandle
);
306 Status
= _SEH_GetExceptionCode();
310 if(!NT_SUCCESS(Status
))
316 DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
317 ObjectAttributes
->ObjectName
);
319 Status
= ObOpenObjectByName(ObjectAttributes
,
326 if(NT_SUCCESS(Status
))
334 Status
= _SEH_GetExceptionCode();
343 /**********************************************************************
345 * NtQuerySymbolicLinkObject
357 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle
,
358 OUT PUNICODE_STRING LinkTarget
,
359 OUT PULONG ResultLength OPTIONAL
)
361 UNICODE_STRING SafeLinkTarget
;
362 PSYMLINK_OBJECT SymlinkObject
;
363 KPROCESSOR_MODE PreviousMode
;
364 NTSTATUS Status
= STATUS_SUCCESS
;
368 PreviousMode
= ExGetPreviousMode();
370 if(PreviousMode
!= KernelMode
)
374 /* probe the unicode string and buffers supplied */
375 ProbeForWrite(LinkTarget
,
376 sizeof(UNICODE_STRING
),
378 SafeLinkTarget
= *LinkTarget
;
379 ProbeForWrite(SafeLinkTarget
.Buffer
,
380 SafeLinkTarget
.MaximumLength
,
383 if(ResultLength
!= NULL
)
385 ProbeForWriteUlong(ResultLength
);
390 Status
= _SEH_GetExceptionCode();
394 if(!NT_SUCCESS(Status
))
401 SafeLinkTarget
= *LinkTarget
;
404 Status
= ObReferenceObjectByHandle(LinkHandle
,
408 (PVOID
*)&SymlinkObject
,
410 if (NT_SUCCESS(Status
))
412 ULONG LengthRequired
= SymlinkObject
->TargetName
.Length
+ sizeof(WCHAR
);
416 if(SafeLinkTarget
.MaximumLength
>= LengthRequired
)
418 /* don't pass TargetLink to RtlCopyUnicodeString here because the caller
419 might have modified the structure which could lead to a copy into
421 RtlCopyUnicodeString(&SafeLinkTarget
,
422 &SymlinkObject
->TargetName
);
423 SafeLinkTarget
.Buffer
[SafeLinkTarget
.Length
/ sizeof(WCHAR
)] = L
'\0';
424 /* copy back the new UNICODE_STRING structure */
425 *LinkTarget
= SafeLinkTarget
;
429 Status
= STATUS_BUFFER_TOO_SMALL
;
432 if(ResultLength
!= NULL
)
434 *ResultLength
= LengthRequired
;
439 Status
= _SEH_GetExceptionCode();
443 ObDereferenceObject(SymlinkObject
);