Fix splitting of cells (noticed by Hartmut).
[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 NTAPI
135 ObInitSymbolicLinkImplementation (VOID)
136 {
137 UNICODE_STRING Name;
138 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
139
140 DPRINT("Creating SymLink Object Type\n");
141
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);
154 }
155
156
157 /**********************************************************************
158 * NAME EXPORTED
159 * NtCreateSymbolicLinkObject
160 *
161 * DESCRIPTION
162 *
163 * ARGUMENTS
164 *
165 * RETURN VALUE
166 *
167 * REVISIONS
168 *
169 */
170 NTSTATUS STDCALL
171 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
172 IN ACCESS_MASK DesiredAccess,
173 IN POBJECT_ATTRIBUTES ObjectAttributes,
174 IN PUNICODE_STRING LinkTarget)
175 {
176 HANDLE hLink;
177 PSYMLINK_OBJECT SymbolicLink;
178 UNICODE_STRING CapturedLinkTarget;
179 KPROCESSOR_MODE PreviousMode;
180 NTSTATUS Status = STATUS_SUCCESS;
181
182 PAGED_CODE();
183
184 PreviousMode = ExGetPreviousMode();
185
186 if(PreviousMode != KernelMode)
187 {
188 _SEH_TRY
189 {
190 ProbeForWriteHandle(LinkHandle);
191 }
192 _SEH_HANDLE
193 {
194 Status = _SEH_GetExceptionCode();
195 }
196 _SEH_END;
197
198 if(!NT_SUCCESS(Status))
199 {
200 return Status;
201 }
202 }
203
204 Status = ProbeAndCaptureUnicodeString(&CapturedLinkTarget,
205 PreviousMode,
206 LinkTarget);
207 if(!NT_SUCCESS(Status))
208 {
209 DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
210 return Status;
211 }
212
213 DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, LinkTarget %wZ)\n",
214 LinkHandle,
215 DesiredAccess,
216 ObjectAttributes,
217 &CapturedLinkTarget);
218
219 Status = ObCreateObject(ExGetPreviousMode(),
220 ObSymbolicLinkType,
221 ObjectAttributes,
222 PreviousMode,
223 NULL,
224 sizeof(SYMLINK_OBJECT),
225 0,
226 0,
227 (PVOID*)&SymbolicLink);
228 if (NT_SUCCESS(Status))
229 {
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,
236 TAG_SYMLINK_TARGET);
237 RtlCopyUnicodeString(&SymbolicLink->TargetName,
238 &CapturedLinkTarget);
239
240 DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
241
242 ZwQuerySystemTime (&SymbolicLink->CreateTime);
243
244 Status = ObInsertObject ((PVOID)SymbolicLink,
245 NULL,
246 DesiredAccess,
247 0,
248 NULL,
249 &hLink);
250 if (NT_SUCCESS(Status))
251 {
252 _SEH_TRY
253 {
254 *LinkHandle = hLink;
255 }
256 _SEH_HANDLE
257 {
258 Status = _SEH_GetExceptionCode();
259 }
260 _SEH_END;
261 }
262 ObDereferenceObject(SymbolicLink);
263 }
264
265 ReleaseCapturedUnicodeString(&CapturedLinkTarget,
266 PreviousMode);
267
268 return Status;
269 }
270
271
272 /**********************************************************************
273 * NAME EXPORTED
274 * NtOpenSymbolicLinkObject
275 *
276 * DESCRIPTION
277 *
278 * ARGUMENTS
279 *
280 * RETURN VALUE
281 *
282 * REVISIONS
283 *
284 */
285 NTSTATUS STDCALL
286 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
287 IN ACCESS_MASK DesiredAccess,
288 IN POBJECT_ATTRIBUTES ObjectAttributes)
289 {
290 HANDLE hLink;
291 KPROCESSOR_MODE PreviousMode;
292 NTSTATUS Status = STATUS_SUCCESS;
293
294 PAGED_CODE();
295
296 PreviousMode = ExGetPreviousMode();
297
298 if(PreviousMode != KernelMode)
299 {
300 _SEH_TRY
301 {
302 ProbeForWriteHandle(LinkHandle);
303 }
304 _SEH_HANDLE
305 {
306 Status = _SEH_GetExceptionCode();
307 }
308 _SEH_END;
309
310 if(!NT_SUCCESS(Status))
311 {
312 return Status;
313 }
314 }
315
316 DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
317 ObjectAttributes->ObjectName);
318
319 Status = ObOpenObjectByName(ObjectAttributes,
320 ObSymbolicLinkType,
321 NULL,
322 PreviousMode,
323 DesiredAccess,
324 NULL,
325 &hLink);
326 if(NT_SUCCESS(Status))
327 {
328 _SEH_TRY
329 {
330 *LinkHandle = hLink;
331 }
332 _SEH_HANDLE
333 {
334 Status = _SEH_GetExceptionCode();
335 }
336 _SEH_END;
337 }
338
339 return Status;
340 }
341
342
343 /**********************************************************************
344 * NAME EXPORTED
345 * NtQuerySymbolicLinkObject
346 *
347 * DESCRIPTION
348 *
349 * ARGUMENTS
350 *
351 * RETURN VALUE
352 *
353 * REVISIONS
354 *
355 */
356 NTSTATUS STDCALL
357 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
358 OUT PUNICODE_STRING LinkTarget,
359 OUT PULONG ResultLength OPTIONAL)
360 {
361 UNICODE_STRING SafeLinkTarget;
362 PSYMLINK_OBJECT SymlinkObject;
363 KPROCESSOR_MODE PreviousMode;
364 NTSTATUS Status = STATUS_SUCCESS;
365
366 PAGED_CODE();
367
368 PreviousMode = ExGetPreviousMode();
369
370 if(PreviousMode != KernelMode)
371 {
372 _SEH_TRY
373 {
374 /* probe the unicode string and buffers supplied */
375 ProbeForWrite(LinkTarget,
376 sizeof(UNICODE_STRING),
377 sizeof(ULONG));
378 SafeLinkTarget = *LinkTarget;
379 ProbeForWrite(SafeLinkTarget.Buffer,
380 SafeLinkTarget.MaximumLength,
381 sizeof(WCHAR));
382
383 if(ResultLength != NULL)
384 {
385 ProbeForWriteUlong(ResultLength);
386 }
387 }
388 _SEH_HANDLE
389 {
390 Status = _SEH_GetExceptionCode();
391 }
392 _SEH_END;
393
394 if(!NT_SUCCESS(Status))
395 {
396 return Status;
397 }
398 }
399 else
400 {
401 SafeLinkTarget = *LinkTarget;
402 }
403
404 Status = ObReferenceObjectByHandle(LinkHandle,
405 SYMBOLIC_LINK_QUERY,
406 ObSymbolicLinkType,
407 PreviousMode,
408 (PVOID *)&SymlinkObject,
409 NULL);
410 if (NT_SUCCESS(Status))
411 {
412 ULONG LengthRequired = SymlinkObject->TargetName.Length + sizeof(WCHAR);
413
414 _SEH_TRY
415 {
416 if(SafeLinkTarget.MaximumLength >= LengthRequired)
417 {
418 /* don't pass TargetLink to RtlCopyUnicodeString here because the caller
419 might have modified the structure which could lead to a copy into
420 kernel memory! */
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;
426 }
427 else
428 {
429 Status = STATUS_BUFFER_TOO_SMALL;
430 }
431
432 if(ResultLength != NULL)
433 {
434 *ResultLength = LengthRequired;
435 }
436 }
437 _SEH_HANDLE
438 {
439 Status = _SEH_GetExceptionCode();
440 }
441 _SEH_END;
442
443 ObDereferenceObject(SymlinkObject);
444 }
445
446 return Status;
447 }
448
449 /* EOF */