Removed incorrect Create/DuplicationNotify callbacks and replaced by a more correct...
[reactos.git] / reactos / ntoskrnl / ob / symlink.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/symlink.c
6 * PURPOSE: Implements symbolic links
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17
18 /* GLOBALS ******************************************************************/
19
20 POBJECT_TYPE ObSymbolicLinkType = NULL;
21
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};
27
28 #define TAG_SYMLINK_TTARGET TAG('S', 'Y', 'T', 'T')
29 #define TAG_SYMLINK_TARGET TAG('S', 'Y', 'M', 'T')
30
31
32 /* FUNCTIONS ****************************************************************/
33
34 /**********************************************************************
35 * NAME INTERNAL
36 * ObpDeleteSymbolicLink
37 *
38 * DESCRIPTION
39 *
40 * ARGUMENTS
41 *
42 * RETURNN VALUE
43 * Status.
44 *
45 * REVISIONS
46 */
47 VOID STDCALL
48 ObpDeleteSymbolicLink(PVOID ObjectBody)
49 {
50 PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT)ObjectBody;
51
52 ExFreePool(SymlinkObject->TargetName.Buffer);
53 }
54
55
56 /**********************************************************************
57 * NAME INTERNAL
58 * ObpParseSymbolicLink
59 *
60 * DESCRIPTION
61 *
62 * ARGUMENTS
63 *
64 * RETURN VALUE
65 *
66 * REVISIONS
67 */
68 NTSTATUS STDCALL
69 ObpParseSymbolicLink(PVOID Object,
70 PVOID * NextObject,
71 PUNICODE_STRING FullPath,
72 PWSTR * RemainingPath,
73 ULONG Attributes)
74 {
75 PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT) Object;
76 UNICODE_STRING TargetPath;
77
78 DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath);
79
80 /*
81 * Stop parsing if the entire path has been parsed and
82 * the desired object is a symbolic link object.
83 */
84 if (((*RemainingPath == NULL) || (**RemainingPath == 0)) &&
85 (Attributes & OBJ_OPENLINK))
86 {
87 DPRINT("Parsing stopped!\n");
88 *NextObject = NULL;
89 return(STATUS_SUCCESS);
90 }
91
92 /* build the expanded path */
93 TargetPath.MaximumLength = SymlinkObject->TargetName.Length + sizeof(WCHAR);
94 if (RemainingPath && *RemainingPath)
95 {
96 TargetPath.MaximumLength += (wcslen(*RemainingPath) * sizeof(WCHAR));
97 }
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)
104 {
105 wcscat(TargetPath.Buffer, *RemainingPath);
106 }
107
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;
113
114 /* reinitialize RemainingPath for reparsing */
115 *RemainingPath = FullPath->Buffer;
116
117 *NextObject = NULL;
118 return STATUS_REPARSE;
119 }
120
121
122 /**********************************************************************
123 * NAME INTERNAL
124 * ObInitSymbolicLinkImplementation
125 *
126 * DESCRIPTION
127 *
128 * ARGUMENTS
129 * None.
130 *
131 * RETURNN VALUE
132 * None.
133 *
134 * REVISIONS
135 */
136 VOID INIT_FUNCTION
137 ObInitSymbolicLinkImplementation (VOID)
138 {
139 ObSymbolicLinkType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
140
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;
158
159 RtlInitUnicodeString(&ObSymbolicLinkType->TypeName,
160 L"SymbolicLink");
161
162 ObpCreateTypeObject(ObSymbolicLinkType);
163 }
164
165
166 /**********************************************************************
167 * NAME EXPORTED
168 * NtCreateSymbolicLinkObject
169 *
170 * DESCRIPTION
171 *
172 * ARGUMENTS
173 *
174 * RETURN VALUE
175 *
176 * REVISIONS
177 *
178 */
179 NTSTATUS STDCALL
180 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
181 IN ACCESS_MASK DesiredAccess,
182 IN POBJECT_ATTRIBUTES ObjectAttributes,
183 IN PUNICODE_STRING LinkTarget)
184 {
185 HANDLE hLink;
186 PSYMLINK_OBJECT SymbolicLink;
187 UNICODE_STRING CapturedLinkTarget;
188 KPROCESSOR_MODE PreviousMode;
189 NTSTATUS Status = STATUS_SUCCESS;
190
191 PAGED_CODE();
192
193 PreviousMode = ExGetPreviousMode();
194
195 if(PreviousMode != KernelMode)
196 {
197 _SEH_TRY
198 {
199 ProbeForWrite(LinkHandle,
200 sizeof(HANDLE),
201 sizeof(ULONG));
202 }
203 _SEH_HANDLE
204 {
205 Status = _SEH_GetExceptionCode();
206 }
207 _SEH_END;
208
209 if(!NT_SUCCESS(Status))
210 {
211 return Status;
212 }
213 }
214
215 Status = RtlCaptureUnicodeString(&CapturedLinkTarget,
216 PreviousMode,
217 PagedPool,
218 FALSE,
219 LinkTarget);
220 if(!NT_SUCCESS(Status))
221 {
222 DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
223 return Status;
224 }
225
226 DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, LinkTarget %wZ)\n",
227 LinkHandle,
228 DesiredAccess,
229 ObjectAttributes,
230 &CapturedLinkTarget);
231
232 Status = ObCreateObject(ExGetPreviousMode(),
233 ObSymbolicLinkType,
234 ObjectAttributes,
235 PreviousMode,
236 NULL,
237 sizeof(SYMLINK_OBJECT),
238 0,
239 0,
240 (PVOID*)&SymbolicLink);
241 if (NT_SUCCESS(Status))
242 {
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,
249 TAG_SYMLINK_TARGET);
250 RtlCopyUnicodeString(&SymbolicLink->TargetName,
251 &CapturedLinkTarget);
252
253 DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
254
255 ZwQuerySystemTime (&SymbolicLink->CreateTime);
256
257 Status = ObInsertObject ((PVOID)SymbolicLink,
258 NULL,
259 DesiredAccess,
260 0,
261 NULL,
262 &hLink);
263 if (NT_SUCCESS(Status))
264 {
265 _SEH_TRY
266 {
267 *LinkHandle = hLink;
268 }
269 _SEH_HANDLE
270 {
271 Status = _SEH_GetExceptionCode();
272 }
273 _SEH_END;
274 }
275 ObDereferenceObject(SymbolicLink);
276 }
277
278 RtlReleaseCapturedUnicodeString(&CapturedLinkTarget,
279 PreviousMode,
280 FALSE);
281
282 return Status;
283 }
284
285
286 /**********************************************************************
287 * NAME EXPORTED
288 * NtOpenSymbolicLinkObject
289 *
290 * DESCRIPTION
291 *
292 * ARGUMENTS
293 *
294 * RETURN VALUE
295 *
296 * REVISIONS
297 *
298 */
299 NTSTATUS STDCALL
300 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
301 IN ACCESS_MASK DesiredAccess,
302 IN POBJECT_ATTRIBUTES ObjectAttributes)
303 {
304 HANDLE hLink;
305 KPROCESSOR_MODE PreviousMode;
306 NTSTATUS Status = STATUS_SUCCESS;
307
308 PAGED_CODE();
309
310 PreviousMode = ExGetPreviousMode();
311
312 if(PreviousMode != KernelMode)
313 {
314 _SEH_TRY
315 {
316 ProbeForWrite(LinkHandle,
317 sizeof(HANDLE),
318 sizeof(ULONG));
319 }
320 _SEH_HANDLE
321 {
322 Status = _SEH_GetExceptionCode();
323 }
324 _SEH_END;
325
326 if(!NT_SUCCESS(Status))
327 {
328 return Status;
329 }
330 }
331
332 DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
333 ObjectAttributes->ObjectName);
334
335 Status = ObOpenObjectByName(ObjectAttributes,
336 ObSymbolicLinkType,
337 NULL,
338 PreviousMode,
339 DesiredAccess,
340 NULL,
341 &hLink);
342 if(NT_SUCCESS(Status))
343 {
344 _SEH_TRY
345 {
346 *LinkHandle = hLink;
347 }
348 _SEH_HANDLE
349 {
350 Status = _SEH_GetExceptionCode();
351 }
352 _SEH_END;
353 }
354
355 return Status;
356 }
357
358
359 /**********************************************************************
360 * NAME EXPORTED
361 * NtQuerySymbolicLinkObject
362 *
363 * DESCRIPTION
364 *
365 * ARGUMENTS
366 *
367 * RETURN VALUE
368 *
369 * REVISIONS
370 *
371 */
372 NTSTATUS STDCALL
373 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
374 OUT PUNICODE_STRING LinkTarget,
375 OUT PULONG ResultLength OPTIONAL)
376 {
377 UNICODE_STRING SafeLinkTarget;
378 PSYMLINK_OBJECT SymlinkObject;
379 KPROCESSOR_MODE PreviousMode;
380 NTSTATUS Status = STATUS_SUCCESS;
381
382 PAGED_CODE();
383
384 PreviousMode = ExGetPreviousMode();
385
386 if(PreviousMode != KernelMode)
387 {
388 _SEH_TRY
389 {
390 /* probe the unicode string and buffers supplied */
391 ProbeForWrite(LinkTarget,
392 sizeof(UNICODE_STRING),
393 sizeof(ULONG));
394 SafeLinkTarget = *LinkTarget;
395 ProbeForWrite(SafeLinkTarget.Buffer,
396 SafeLinkTarget.MaximumLength,
397 sizeof(WCHAR));
398
399 if(ResultLength != NULL)
400 {
401 ProbeForWrite(ResultLength,
402 sizeof(ULONG),
403 sizeof(ULONG));
404 }
405 }
406 _SEH_HANDLE
407 {
408 Status = _SEH_GetExceptionCode();
409 }
410 _SEH_END;
411
412 if(!NT_SUCCESS(Status))
413 {
414 return Status;
415 }
416 }
417 else
418 {
419 SafeLinkTarget = *LinkTarget;
420 }
421
422 Status = ObReferenceObjectByHandle(LinkHandle,
423 SYMBOLIC_LINK_QUERY,
424 ObSymbolicLinkType,
425 PreviousMode,
426 (PVOID *)&SymlinkObject,
427 NULL);
428 if (NT_SUCCESS(Status))
429 {
430 ULONG LengthRequired = SymlinkObject->TargetName.Length + sizeof(WCHAR);
431
432 _SEH_TRY
433 {
434 if(SafeLinkTarget.MaximumLength >= LengthRequired)
435 {
436 /* don't pass TargetLink to RtlCopyUnicodeString here because the caller
437 might have modified the structure which could lead to a copy into
438 kernel memory! */
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;
444 }
445 else
446 {
447 Status = STATUS_BUFFER_TOO_SMALL;
448 }
449
450 if(ResultLength != NULL)
451 {
452 *ResultLength = LengthRequired;
453 }
454 }
455 _SEH_HANDLE
456 {
457 Status = _SEH_GetExceptionCode();
458 }
459 _SEH_END;
460
461 ObDereferenceObject(SymlinkObject);
462 }
463
464 return Status;
465 }
466
467 /* EOF */