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
137 ObInitSymbolicLinkImplementation (VOID
)
139 ObSymbolicLinkType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
141 ObSymbolicLinkType
->Tag
= TAG('S', 'Y', 'M', 'T');
142 ObSymbolicLinkType
->TotalObjects
= 0;
143 ObSymbolicLinkType
->TotalHandles
= 0;
144 ObSymbolicLinkType
->PeakObjects
= 0;
145 ObSymbolicLinkType
->PeakHandles
= 0;
146 ObSymbolicLinkType
->PagedPoolCharge
= 0;
147 ObSymbolicLinkType
->NonpagedPoolCharge
= sizeof(SYMLINK_OBJECT
);
148 ObSymbolicLinkType
->Mapping
= &ObpSymbolicLinkMapping
;
149 ObSymbolicLinkType
->Dump
= NULL
;
150 ObSymbolicLinkType
->Open
= NULL
;
151 ObSymbolicLinkType
->Close
= NULL
;
152 ObSymbolicLinkType
->Delete
= ObpDeleteSymbolicLink
;
153 ObSymbolicLinkType
->Parse
= ObpParseSymbolicLink
;
154 ObSymbolicLinkType
->Security
= NULL
;
155 ObSymbolicLinkType
->Open
= NULL
;
156 ObSymbolicLinkType
->QueryName
= NULL
;
157 ObSymbolicLinkType
->OkayToClose
= NULL
;
159 RtlInitUnicodeString(&ObSymbolicLinkType
->TypeName
,
162 ObpCreateTypeObject(ObSymbolicLinkType
);
166 /**********************************************************************
168 * NtCreateSymbolicLinkObject
180 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle
,
181 IN ACCESS_MASK DesiredAccess
,
182 IN POBJECT_ATTRIBUTES ObjectAttributes
,
183 IN PUNICODE_STRING LinkTarget
)
186 PSYMLINK_OBJECT SymbolicLink
;
187 UNICODE_STRING CapturedLinkTarget
;
188 KPROCESSOR_MODE PreviousMode
;
189 NTSTATUS Status
= STATUS_SUCCESS
;
193 PreviousMode
= ExGetPreviousMode();
195 if(PreviousMode
!= KernelMode
)
199 ProbeForWrite(LinkHandle
,
205 Status
= _SEH_GetExceptionCode();
209 if(!NT_SUCCESS(Status
))
215 Status
= RtlCaptureUnicodeString(&CapturedLinkTarget
,
220 if(!NT_SUCCESS(Status
))
222 DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
226 DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, LinkTarget %wZ)\n",
230 &CapturedLinkTarget
);
232 Status
= ObCreateObject(ExGetPreviousMode(),
237 sizeof(SYMLINK_OBJECT
),
240 (PVOID
*)&SymbolicLink
);
241 if (NT_SUCCESS(Status
))
243 SymbolicLink
->TargetName
.Length
= 0;
244 SymbolicLink
->TargetName
.MaximumLength
=
245 ((wcslen(LinkTarget
->Buffer
) + 1) * sizeof(WCHAR
));
246 SymbolicLink
->TargetName
.Buffer
=
247 ExAllocatePoolWithTag(NonPagedPool
,
248 SymbolicLink
->TargetName
.MaximumLength
,
250 RtlCopyUnicodeString(&SymbolicLink
->TargetName
,
251 &CapturedLinkTarget
);
253 DPRINT("DeviceName %S\n", SymbolicLink
->TargetName
.Buffer
);
255 ZwQuerySystemTime (&SymbolicLink
->CreateTime
);
257 Status
= ObInsertObject ((PVOID
)SymbolicLink
,
263 if (NT_SUCCESS(Status
))
271 Status
= _SEH_GetExceptionCode();
275 ObDereferenceObject(SymbolicLink
);
278 RtlReleaseCapturedUnicodeString(&CapturedLinkTarget
,
286 /**********************************************************************
288 * NtOpenSymbolicLinkObject
300 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle
,
301 IN ACCESS_MASK DesiredAccess
,
302 IN POBJECT_ATTRIBUTES ObjectAttributes
)
305 KPROCESSOR_MODE PreviousMode
;
306 NTSTATUS Status
= STATUS_SUCCESS
;
310 PreviousMode
= ExGetPreviousMode();
312 if(PreviousMode
!= KernelMode
)
316 ProbeForWrite(LinkHandle
,
322 Status
= _SEH_GetExceptionCode();
326 if(!NT_SUCCESS(Status
))
332 DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
333 ObjectAttributes
->ObjectName
);
335 Status
= ObOpenObjectByName(ObjectAttributes
,
342 if(NT_SUCCESS(Status
))
350 Status
= _SEH_GetExceptionCode();
359 /**********************************************************************
361 * NtQuerySymbolicLinkObject
373 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle
,
374 OUT PUNICODE_STRING LinkTarget
,
375 OUT PULONG ResultLength OPTIONAL
)
377 UNICODE_STRING SafeLinkTarget
;
378 PSYMLINK_OBJECT SymlinkObject
;
379 KPROCESSOR_MODE PreviousMode
;
380 NTSTATUS Status
= STATUS_SUCCESS
;
384 PreviousMode
= ExGetPreviousMode();
386 if(PreviousMode
!= KernelMode
)
390 /* probe the unicode string and buffers supplied */
391 ProbeForWrite(LinkTarget
,
392 sizeof(UNICODE_STRING
),
394 SafeLinkTarget
= *LinkTarget
;
395 ProbeForWrite(SafeLinkTarget
.Buffer
,
396 SafeLinkTarget
.MaximumLength
,
399 if(ResultLength
!= NULL
)
401 ProbeForWrite(ResultLength
,
408 Status
= _SEH_GetExceptionCode();
412 if(!NT_SUCCESS(Status
))
419 SafeLinkTarget
= *LinkTarget
;
422 Status
= ObReferenceObjectByHandle(LinkHandle
,
426 (PVOID
*)&SymlinkObject
,
428 if (NT_SUCCESS(Status
))
430 ULONG LengthRequired
= SymlinkObject
->TargetName
.Length
+ sizeof(WCHAR
);
434 if(SafeLinkTarget
.MaximumLength
>= LengthRequired
)
436 /* don't pass TargetLink to RtlCopyUnicodeString here because the caller
437 might have modified the structure which could lead to a copy into
439 RtlCopyUnicodeString(&SafeLinkTarget
,
440 &SymlinkObject
->TargetName
);
441 SafeLinkTarget
.Buffer
[SafeLinkTarget
.Length
/ sizeof(WCHAR
)] = L
'\0';
442 /* copy back the new UNICODE_STRING structure */
443 *LinkTarget
= SafeLinkTarget
;
447 Status
= STATUS_BUFFER_TOO_SMALL
;
450 if(ResultLength
!= NULL
)
452 *ResultLength
= LengthRequired
;
457 Status
= _SEH_GetExceptionCode();
461 ObDereferenceObject(SymlinkObject
);