- use inlined probing macros for basic types
[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 /* FUNCTIONS ****************************************************************/
29
30 /**********************************************************************
31 * NAME INTERNAL
32 * ObpDeleteSymbolicLink
33 *
34 * DESCRIPTION
35 *
36 * ARGUMENTS
37 *
38 * RETURNN VALUE
39 * Status.
40 *
41 * REVISIONS
42 */
43 VOID STDCALL
44 ObpDeleteSymbolicLink(PVOID ObjectBody)
45 {
46 PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT)ObjectBody;
47
48 ExFreePool(SymlinkObject->TargetName.Buffer);
49 }
50
51
52 /**********************************************************************
53 * NAME INTERNAL
54 * ObpParseSymbolicLink
55 *
56 * DESCRIPTION
57 *
58 * ARGUMENTS
59 *
60 * RETURN VALUE
61 *
62 * REVISIONS
63 */
64 NTSTATUS STDCALL
65 ObpParseSymbolicLink(PVOID Object,
66 PVOID * NextObject,
67 PUNICODE_STRING FullPath,
68 PWSTR * RemainingPath,
69 ULONG Attributes)
70 {
71 PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT) Object;
72 UNICODE_STRING TargetPath;
73
74 DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath);
75
76 /*
77 * Stop parsing if the entire path has been parsed and
78 * the desired object is a symbolic link object.
79 */
80 if (((*RemainingPath == NULL) || (**RemainingPath == 0)) &&
81 (Attributes & OBJ_OPENLINK))
82 {
83 DPRINT("Parsing stopped!\n");
84 *NextObject = NULL;
85 return(STATUS_SUCCESS);
86 }
87
88 /* build the expanded path */
89 TargetPath.MaximumLength = SymlinkObject->TargetName.Length + sizeof(WCHAR);
90 if (RemainingPath && *RemainingPath)
91 {
92 TargetPath.MaximumLength += (wcslen(*RemainingPath) * sizeof(WCHAR));
93 }
94 TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
95 TargetPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
96 TargetPath.MaximumLength,
97 TAG_SYMLINK_TTARGET);
98 wcscpy(TargetPath.Buffer, SymlinkObject->TargetName.Buffer);
99 if (RemainingPath && *RemainingPath)
100 {
101 wcscat(TargetPath.Buffer, *RemainingPath);
102 }
103
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;
109
110 /* reinitialize RemainingPath for reparsing */
111 *RemainingPath = FullPath->Buffer;
112
113 *NextObject = NULL;
114 return STATUS_REPARSE;
115 }
116
117
118 /**********************************************************************
119 * NAME INTERNAL
120 * ObInitSymbolicLinkImplementation
121 *
122 * DESCRIPTION
123 *
124 * ARGUMENTS
125 * None.
126 *
127 * RETURNN VALUE
128 * None.
129 *
130 * REVISIONS
131 */
132 VOID
133 INIT_FUNCTION
134 ObInitSymbolicLinkImplementation (VOID)
135 {
136 UNICODE_STRING Name;
137 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
138
139 DPRINT("Creating SymLink Object Type\n");
140
141 /* Initialize the Directory type */
142 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
143 RtlInitUnicodeString(&Name, L"SymbolicLink");
144 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
145 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(SYMLINK_OBJECT);
146 ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping;
147 ObjectTypeInitializer.PoolType = NonPagedPool;
148 ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS;
149 ObjectTypeInitializer.UseDefaultObject = TRUE;
150 ObjectTypeInitializer.ParseProcedure = ObpParseSymbolicLink;
151 ObjectTypeInitializer.DeleteProcedure = ObpDeleteSymbolicLink;
152 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObSymbolicLinkType);
153 }
154
155
156 /**********************************************************************
157 * NAME EXPORTED
158 * NtCreateSymbolicLinkObject
159 *
160 * DESCRIPTION
161 *
162 * ARGUMENTS
163 *
164 * RETURN VALUE
165 *
166 * REVISIONS
167 *
168 */
169 NTSTATUS STDCALL
170 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
171 IN ACCESS_MASK DesiredAccess,
172 IN POBJECT_ATTRIBUTES ObjectAttributes,
173 IN PUNICODE_STRING LinkTarget)
174 {
175 HANDLE hLink;
176 PSYMLINK_OBJECT SymbolicLink;
177 UNICODE_STRING CapturedLinkTarget;
178 KPROCESSOR_MODE PreviousMode;
179 NTSTATUS Status = STATUS_SUCCESS;
180
181 PAGED_CODE();
182
183 PreviousMode = ExGetPreviousMode();
184
185 if(PreviousMode != KernelMode)
186 {
187 _SEH_TRY
188 {
189 ProbeForWriteHandle(LinkHandle);
190 }
191 _SEH_HANDLE
192 {
193 Status = _SEH_GetExceptionCode();
194 }
195 _SEH_END;
196
197 if(!NT_SUCCESS(Status))
198 {
199 return Status;
200 }
201 }
202
203 Status = RtlCaptureUnicodeString(&CapturedLinkTarget,
204 PreviousMode,
205 PagedPool,
206 FALSE,
207 LinkTarget);
208 if(!NT_SUCCESS(Status))
209 {
210 DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
211 return Status;
212 }
213
214 DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, LinkTarget %wZ)\n",
215 LinkHandle,
216 DesiredAccess,
217 ObjectAttributes,
218 &CapturedLinkTarget);
219
220 Status = ObCreateObject(ExGetPreviousMode(),
221 ObSymbolicLinkType,
222 ObjectAttributes,
223 PreviousMode,
224 NULL,
225 sizeof(SYMLINK_OBJECT),
226 0,
227 0,
228 (PVOID*)&SymbolicLink);
229 if (NT_SUCCESS(Status))
230 {
231 SymbolicLink->TargetName.Length = 0;
232 SymbolicLink->TargetName.MaximumLength =
233 ((wcslen(LinkTarget->Buffer) + 1) * sizeof(WCHAR));
234 SymbolicLink->TargetName.Buffer =
235 ExAllocatePoolWithTag(NonPagedPool,
236 SymbolicLink->TargetName.MaximumLength,
237 TAG_SYMLINK_TARGET);
238 RtlCopyUnicodeString(&SymbolicLink->TargetName,
239 &CapturedLinkTarget);
240
241 DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
242
243 ZwQuerySystemTime (&SymbolicLink->CreateTime);
244
245 Status = ObInsertObject ((PVOID)SymbolicLink,
246 NULL,
247 DesiredAccess,
248 0,
249 NULL,
250 &hLink);
251 if (NT_SUCCESS(Status))
252 {
253 _SEH_TRY
254 {
255 *LinkHandle = hLink;
256 }
257 _SEH_HANDLE
258 {
259 Status = _SEH_GetExceptionCode();
260 }
261 _SEH_END;
262 }
263 ObDereferenceObject(SymbolicLink);
264 }
265
266 RtlReleaseCapturedUnicodeString(&CapturedLinkTarget,
267 PreviousMode,
268 FALSE);
269
270 return Status;
271 }
272
273
274 /**********************************************************************
275 * NAME EXPORTED
276 * NtOpenSymbolicLinkObject
277 *
278 * DESCRIPTION
279 *
280 * ARGUMENTS
281 *
282 * RETURN VALUE
283 *
284 * REVISIONS
285 *
286 */
287 NTSTATUS STDCALL
288 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
289 IN ACCESS_MASK DesiredAccess,
290 IN POBJECT_ATTRIBUTES ObjectAttributes)
291 {
292 HANDLE hLink;
293 KPROCESSOR_MODE PreviousMode;
294 NTSTATUS Status = STATUS_SUCCESS;
295
296 PAGED_CODE();
297
298 PreviousMode = ExGetPreviousMode();
299
300 if(PreviousMode != KernelMode)
301 {
302 _SEH_TRY
303 {
304 ProbeForWriteHandle(LinkHandle);
305 }
306 _SEH_HANDLE
307 {
308 Status = _SEH_GetExceptionCode();
309 }
310 _SEH_END;
311
312 if(!NT_SUCCESS(Status))
313 {
314 return Status;
315 }
316 }
317
318 DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
319 ObjectAttributes->ObjectName);
320
321 Status = ObOpenObjectByName(ObjectAttributes,
322 ObSymbolicLinkType,
323 NULL,
324 PreviousMode,
325 DesiredAccess,
326 NULL,
327 &hLink);
328 if(NT_SUCCESS(Status))
329 {
330 _SEH_TRY
331 {
332 *LinkHandle = hLink;
333 }
334 _SEH_HANDLE
335 {
336 Status = _SEH_GetExceptionCode();
337 }
338 _SEH_END;
339 }
340
341 return Status;
342 }
343
344
345 /**********************************************************************
346 * NAME EXPORTED
347 * NtQuerySymbolicLinkObject
348 *
349 * DESCRIPTION
350 *
351 * ARGUMENTS
352 *
353 * RETURN VALUE
354 *
355 * REVISIONS
356 *
357 */
358 NTSTATUS STDCALL
359 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
360 OUT PUNICODE_STRING LinkTarget,
361 OUT PULONG ResultLength OPTIONAL)
362 {
363 UNICODE_STRING SafeLinkTarget;
364 PSYMLINK_OBJECT SymlinkObject;
365 KPROCESSOR_MODE PreviousMode;
366 NTSTATUS Status = STATUS_SUCCESS;
367
368 PAGED_CODE();
369
370 PreviousMode = ExGetPreviousMode();
371
372 if(PreviousMode != KernelMode)
373 {
374 _SEH_TRY
375 {
376 /* probe the unicode string and buffers supplied */
377 ProbeForWrite(LinkTarget,
378 sizeof(UNICODE_STRING),
379 sizeof(ULONG));
380 SafeLinkTarget = *LinkTarget;
381 ProbeForWrite(SafeLinkTarget.Buffer,
382 SafeLinkTarget.MaximumLength,
383 sizeof(WCHAR));
384
385 if(ResultLength != NULL)
386 {
387 ProbeForWriteUlong(ResultLength);
388 }
389 }
390 _SEH_HANDLE
391 {
392 Status = _SEH_GetExceptionCode();
393 }
394 _SEH_END;
395
396 if(!NT_SUCCESS(Status))
397 {
398 return Status;
399 }
400 }
401 else
402 {
403 SafeLinkTarget = *LinkTarget;
404 }
405
406 Status = ObReferenceObjectByHandle(LinkHandle,
407 SYMBOLIC_LINK_QUERY,
408 ObSymbolicLinkType,
409 PreviousMode,
410 (PVOID *)&SymlinkObject,
411 NULL);
412 if (NT_SUCCESS(Status))
413 {
414 ULONG LengthRequired = SymlinkObject->TargetName.Length + sizeof(WCHAR);
415
416 _SEH_TRY
417 {
418 if(SafeLinkTarget.MaximumLength >= LengthRequired)
419 {
420 /* don't pass TargetLink to RtlCopyUnicodeString here because the caller
421 might have modified the structure which could lead to a copy into
422 kernel memory! */
423 RtlCopyUnicodeString(&SafeLinkTarget,
424 &SymlinkObject->TargetName);
425 SafeLinkTarget.Buffer[SafeLinkTarget.Length / sizeof(WCHAR)] = L'\0';
426 /* copy back the new UNICODE_STRING structure */
427 *LinkTarget = SafeLinkTarget;
428 }
429 else
430 {
431 Status = STATUS_BUFFER_TOO_SMALL;
432 }
433
434 if(ResultLength != NULL)
435 {
436 *ResultLength = LengthRequired;
437 }
438 }
439 _SEH_HANDLE
440 {
441 Status = _SEH_GetExceptionCode();
442 }
443 _SEH_END;
444
445 ObDereferenceObject(SymlinkObject);
446 }
447
448 return Status;
449 }
450
451 /* EOF */