* Moved symbolic link implementation to the object manager.
[reactos.git] / reactos / ntoskrnl / ob / object.c
1 /* $Id: object.c,v 1.58 2003/02/25 16:49:08 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/object.c
6 * PURPOSE: Implements generic object managment functions
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * 10/06/98: Created
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <roscfg.h>
16 #include <internal/ob.h>
17 #include <internal/ps.h>
18 #include <internal/id.h>
19 #include <internal/ke.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 /* FUNCTIONS ************************************************************/
25
26 PVOID HEADER_TO_BODY(POBJECT_HEADER obj)
27 {
28 return(((void *)obj)+sizeof(OBJECT_HEADER)-sizeof(COMMON_BODY_HEADER));
29 }
30
31 POBJECT_HEADER BODY_TO_HEADER(PVOID body)
32 {
33 PCOMMON_BODY_HEADER chdr = (PCOMMON_BODY_HEADER)body;
34 return(CONTAINING_RECORD((&(chdr->Type)),OBJECT_HEADER,Type));
35 }
36
37
38 /**********************************************************************
39 * NAME PRIVATE
40 * ObInitializeObject
41 *
42 * DESCRIPTION
43 *
44 * ARGUMENTS
45 *
46 * RETURN VALUE
47 */
48 VOID ObInitializeObject(POBJECT_HEADER ObjectHeader,
49 PHANDLE Handle,
50 ACCESS_MASK DesiredAccess,
51 POBJECT_TYPE Type,
52 POBJECT_ATTRIBUTES ObjectAttributes)
53 {
54 ObjectHeader->HandleCount = 0;
55 ObjectHeader->RefCount = 1;
56 ObjectHeader->ObjectType = Type;
57 if (ObjectAttributes != NULL &&
58 ObjectAttributes->Attributes & OBJ_PERMANENT)
59 {
60 ObjectHeader->Permanent = TRUE;
61 }
62 else
63 {
64 ObjectHeader->Permanent = FALSE;
65 }
66 RtlInitUnicodeString(&(ObjectHeader->Name),NULL);
67 if (Handle != NULL)
68 {
69 ObCreateHandle(PsGetCurrentProcess(),
70 HEADER_TO_BODY(ObjectHeader),
71 DesiredAccess,
72 ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
73 Handle);
74 }
75 }
76
77
78 /**********************************************************************
79 * NAME PRIVATE
80 * ObFindObject@16
81 *
82 * DESCRIPTION
83 *
84 * ARGUMENTS
85 * ObjectAttributes
86 *
87 * ReturnedObject
88 *
89 * RemainigPath
90 * Pointer to a unicode string that will contain the
91 * remaining path if the function returns successfully.
92 * The caller must free the buffer after use by calling
93 * RtlFreeUnicodeString ().
94 *
95 * ObjectType
96 * Optional pointer to an object type. This is used to
97 * descide if a symbolic link object will be parsed or not.
98 *
99 * RETURN VALUE
100 */
101 NTSTATUS ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
102 PVOID* ReturnedObject,
103 PUNICODE_STRING RemainingPath,
104 POBJECT_TYPE ObjectType)
105 {
106 PVOID NextObject;
107 PVOID CurrentObject;
108 PVOID RootObject;
109 POBJECT_HEADER CurrentHeader;
110 NTSTATUS Status;
111 PWSTR Path;
112 PWSTR current;
113 UNICODE_STRING PathString;
114 ULONG Attributes;
115
116 DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
117 "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath);
118 DPRINT("ObjectAttributes->ObjectName %wZ\n",
119 ObjectAttributes->ObjectName);
120
121 RtlInitUnicodeString (RemainingPath, NULL);
122
123 if (ObjectAttributes->RootDirectory == NULL)
124 {
125 ObReferenceObjectByPointer(NameSpaceRoot,
126 DIRECTORY_TRAVERSE,
127 NULL,
128 UserMode);
129 CurrentObject = NameSpaceRoot;
130 }
131 else
132 {
133 Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
134 DIRECTORY_TRAVERSE,
135 NULL,
136 UserMode,
137 &CurrentObject,
138 NULL);
139 if (!NT_SUCCESS(Status))
140 {
141 return(Status);
142 }
143 }
144
145 Path = ObjectAttributes->ObjectName->Buffer;
146
147 if (Path[0] == 0)
148 {
149 *ReturnedObject = CurrentObject;
150 return(STATUS_SUCCESS);
151 }
152
153 if ((ObjectAttributes->RootDirectory == NULL) && (Path[0] != '\\'))
154 {
155 ObDereferenceObject(CurrentObject);
156 return(STATUS_UNSUCCESSFUL);
157 }
158
159 if (Path)
160 {
161 RtlCreateUnicodeString (&PathString, Path);
162 current = PathString.Buffer;
163 }
164 else
165 {
166 RtlInitUnicodeString (&PathString, NULL);
167 current = NULL;
168 }
169
170 RootObject = CurrentObject;
171 Attributes = ObjectAttributes->Attributes;
172 if (ObjectType == ObSymbolicLinkType)
173 Attributes |= OBJ_OPENLINK;
174
175 while (TRUE)
176 {
177 DPRINT("current %S\n",current);
178 CurrentHeader = BODY_TO_HEADER(CurrentObject);
179
180 DPRINT("Current ObjectType %wZ\n",
181 &CurrentHeader->ObjectType->TypeName);
182
183 if (CurrentHeader->ObjectType->Parse == NULL)
184 {
185 DPRINT("Current object can't parse\n");
186 break;
187 }
188 Status = CurrentHeader->ObjectType->Parse(CurrentObject,
189 &NextObject,
190 &PathString,
191 &current,
192 Attributes);
193 if (Status == STATUS_REPARSE)
194 {
195 /* reparse the object path */
196 NextObject = RootObject;
197 current = PathString.Buffer;
198
199 ObReferenceObjectByPointer(NextObject,
200 DIRECTORY_TRAVERSE,
201 NULL,
202 UserMode);
203 }
204
205 if (NextObject == NULL)
206 {
207 break;
208 }
209 ObDereferenceObject(CurrentObject);
210 CurrentObject = NextObject;
211 }
212
213 if (current)
214 RtlCreateUnicodeString (RemainingPath, current);
215 RtlFreeUnicodeString (&PathString);
216 *ReturnedObject = CurrentObject;
217
218 return(STATUS_SUCCESS);
219 }
220
221
222 /**********************************************************************
223 * NAME EXPORTED
224 * ObCreateObject@36
225 *
226 * DESCRIPTION
227 *
228 * ARGUMENTS
229 *
230 * RETURN VALUE
231 */
232 NTSTATUS STDCALL
233 ObCreateObject(OUT PHANDLE Handle,
234 IN ACCESS_MASK DesiredAccess,
235 IN POBJECT_ATTRIBUTES ObjectAttributes,
236 IN POBJECT_TYPE Type,
237 OUT PVOID *Object)
238 {
239 PVOID Parent = NULL;
240 UNICODE_STRING RemainingPath;
241 POBJECT_HEADER Header;
242 POBJECT_HEADER ParentHeader = NULL;
243 NTSTATUS Status;
244 BOOLEAN ObjectAttached = FALSE;
245
246 assert_irql(APC_LEVEL);
247
248 DPRINT("ObCreateObject(Handle %x, ObjectAttributes %x, Type %x)\n",
249 Handle, ObjectAttributes, Type);
250
251 if (ObjectAttributes != NULL &&
252 ObjectAttributes->ObjectName != NULL &&
253 ObjectAttributes->ObjectName->Buffer != NULL)
254 {
255 Status = ObFindObject(ObjectAttributes,
256 &Parent,
257 &RemainingPath,
258 NULL);
259 if (!NT_SUCCESS(Status))
260 {
261 DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status);
262 return(Status);
263 }
264 }
265 else
266 {
267 RtlInitUnicodeString(&RemainingPath, NULL);
268 }
269
270 RtlMapGenericMask(&DesiredAccess,
271 Type->Mapping);
272
273 Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
274 OBJECT_ALLOC_SIZE(Type),
275 Type->Tag);
276 ObInitializeObject(Header,
277 NULL,
278 DesiredAccess,
279 Type,
280 ObjectAttributes);
281
282 if (Parent != NULL)
283 {
284 ParentHeader = BODY_TO_HEADER(Parent);
285 }
286
287 if (ParentHeader != NULL &&
288 ParentHeader->ObjectType == ObDirectoryType &&
289 RemainingPath.Buffer != NULL)
290 {
291 ObpAddEntryDirectory(Parent,
292 Header,
293 RemainingPath.Buffer+1);
294 ObjectAttached = TRUE;
295 }
296
297 if ((Header->ObjectType != NULL) &&
298 (Header->ObjectType->Create != NULL))
299 {
300 DPRINT("Calling %x\n", Header->ObjectType->Create);
301 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
302 Parent,
303 RemainingPath.Buffer,
304 ObjectAttributes);
305 if (!NT_SUCCESS(Status))
306 {
307 if (ObjectAttached == TRUE)
308 {
309 ObpRemoveEntryDirectory(Header);
310 }
311 if (Parent)
312 {
313 ObDereferenceObject(Parent);
314 }
315 RtlFreeUnicodeString(&Header->Name);
316 RtlFreeUnicodeString(&RemainingPath);
317 ExFreePool(Header);
318 return(Status);
319 }
320 }
321 RtlFreeUnicodeString( &RemainingPath );
322
323 if (Object != NULL)
324 {
325 *Object = HEADER_TO_BODY(Header);
326 }
327
328 if (Handle != NULL)
329 {
330 ObCreateHandle(PsGetCurrentProcess(),
331 *Object,
332 DesiredAccess,
333 ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
334 Handle);
335 }
336
337 return(STATUS_SUCCESS);
338 }
339
340
341 NTSTATUS STDCALL
342 ObReferenceObjectByPointer(IN PVOID Object,
343 IN ACCESS_MASK DesiredAccess,
344 IN POBJECT_TYPE ObjectType,
345 IN KPROCESSOR_MODE AccessMode)
346 /*
347 * FUNCTION: Increments the pointer reference count for a given object
348 * ARGUMENTS:
349 * ObjectBody = Object's body
350 * DesiredAccess = Desired access to the object
351 * ObjectType = Points to the object type structure
352 * AccessMode = Type of access check to perform
353 * RETURNS: Status
354 */
355 {
356 POBJECT_HEADER Header;
357
358 // DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
359 // Object,ObjectType);
360
361 Header = BODY_TO_HEADER(Object);
362
363 if (ObjectType != NULL && Header->ObjectType != ObjectType)
364 {
365 DPRINT("Failed %x (type was %x %S) should be %x %S\n",
366 Header,
367 Header->ObjectType,
368 Header->ObjectType->TypeName.Buffer,
369 ObjectType,
370 ObjectType->TypeName.Buffer);
371 return(STATUS_UNSUCCESSFUL);
372 }
373 if (Header->ObjectType == PsProcessType)
374 {
375 DPRINT("Ref p 0x%x refcount %d type %x ",
376 Object, Header->RefCount, PsProcessType);
377 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
378 }
379 if (Header->ObjectType == PsThreadType)
380 {
381 DPRINT("Deref t 0x%x with refcount %d type %x ",
382 Object, Header->RefCount, PsThreadType);
383 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
384 }
385
386 if (Header->CloseInProcess)
387 {
388 return(STATUS_UNSUCCESSFUL);
389 }
390
391 InterlockedIncrement(&Header->RefCount);
392
393 return(STATUS_SUCCESS);
394 }
395
396
397 NTSTATUS STDCALL
398 ObOpenObjectByPointer(IN POBJECT Object,
399 IN ULONG HandleAttributes,
400 IN PACCESS_STATE PassedAccessState,
401 IN ACCESS_MASK DesiredAccess,
402 IN POBJECT_TYPE ObjectType,
403 IN KPROCESSOR_MODE AccessMode,
404 OUT PHANDLE Handle)
405 {
406 NTSTATUS Status;
407
408 DPRINT("ObOpenObjectByPointer()\n");
409
410 Status = ObReferenceObjectByPointer(Object,
411 0,
412 ObjectType,
413 AccessMode);
414 if (!NT_SUCCESS(Status))
415 {
416 return Status;
417 }
418
419 Status = ObCreateHandle(PsGetCurrentProcess(),
420 Object,
421 DesiredAccess,
422 HandleAttributes & OBJ_INHERIT,
423 Handle);
424
425 ObDereferenceObject(Object);
426
427 return STATUS_SUCCESS;
428 }
429
430
431 static NTSTATUS
432 ObpPerformRetentionChecks(POBJECT_HEADER Header)
433 {
434 // DPRINT("ObPerformRetentionChecks(Header %x), RefCount %d, HandleCount %d\n",
435 // Header,Header->RefCount,Header->HandleCount);
436
437 if (Header->RefCount < 0)
438 {
439 CPRINT("Object %x/%x has invalid reference count (%d)\n",
440 Header, HEADER_TO_BODY(Header), Header->RefCount);
441 KeBugCheck(0);
442 }
443 if (Header->HandleCount < 0)
444 {
445 CPRINT("Object %x/%x has invalid handle count (%d)\n",
446 Header, HEADER_TO_BODY(Header), Header->HandleCount);
447 KeBugCheck(0);
448 }
449
450 if (Header->RefCount == 0 &&
451 Header->HandleCount == 0 &&
452 Header->Permanent == FALSE)
453 {
454 if (Header->CloseInProcess)
455 {
456 KeBugCheck(0);
457 return STATUS_UNSUCCESSFUL;
458 }
459 Header->CloseInProcess = TRUE;
460 if (Header->ObjectType != NULL &&
461 Header->ObjectType->Delete != NULL)
462 {
463 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
464 }
465 if (Header->Name.Buffer != NULL)
466 {
467 ObpRemoveEntryDirectory(Header);
468 RtlFreeUnicodeString(&Header->Name);
469 }
470 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
471 ExFreePool(Header);
472 }
473 return(STATUS_SUCCESS);
474 }
475
476
477 /**********************************************************************
478 * NAME EXPORTED
479 * ObfReferenceObject@4
480 *
481 * DESCRIPTION
482 * Increments a given object's reference count and performs
483 * retention checks.
484 *
485 * ARGUMENTS
486 * ObjectBody = Body of the object.
487 *
488 * RETURN VALUE
489 * None.
490 */
491 VOID FASTCALL
492 ObfReferenceObject(IN PVOID Object)
493 {
494 POBJECT_HEADER Header;
495
496 assert(Object);
497
498 Header = BODY_TO_HEADER(Object);
499
500 if (Header->CloseInProcess)
501 {
502 KeBugCheck(0);
503 }
504 InterlockedIncrement(&Header->RefCount);
505
506 ObpPerformRetentionChecks(Header);
507 }
508
509
510 /**********************************************************************
511 * NAME EXPORTED
512 * ObfDereferenceObject@4
513 *
514 * DESCRIPTION
515 * Decrements a given object's reference count and performs
516 * retention checks.
517 *
518 * ARGUMENTS
519 * ObjectBody = Body of the object.
520 *
521 * RETURN VALUE
522 * None.
523 */
524 VOID FASTCALL
525 ObfDereferenceObject(IN PVOID Object)
526 {
527 POBJECT_HEADER Header;
528 extern POBJECT_TYPE PsProcessType;
529
530 assert(Object);
531
532 Header = BODY_TO_HEADER(Object);
533
534 if (Header->ObjectType == PsProcessType)
535 {
536 DPRINT("Deref p 0x%x with refcount %d type %x ",
537 Object, Header->RefCount, PsProcessType);
538 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
539 }
540 if (Header->ObjectType == PsThreadType)
541 {
542 DPRINT("Deref t 0x%x with refcount %d type %x ",
543 Object, Header->RefCount, PsThreadType);
544 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
545 }
546
547 InterlockedDecrement(&Header->RefCount);
548
549 ObpPerformRetentionChecks(Header);
550 }
551
552
553 /**********************************************************************
554 * NAME EXPORTED
555 * ObGetObjectPointerCount@4
556 *
557 * DESCRIPTION
558 * Retrieves the pointer(reference) count of the given object.
559 *
560 * ARGUMENTS
561 * ObjectBody = Body of the object.
562 *
563 * RETURN VALUE
564 * Reference count.
565 */
566 ULONG STDCALL
567 ObGetObjectPointerCount(PVOID Object)
568 {
569 POBJECT_HEADER Header;
570
571 assert(Object);
572 Header = BODY_TO_HEADER(Object);
573
574 return(Header->RefCount);
575 }
576
577
578 /**********************************************************************
579 * NAME INTERNAL
580 * ObGetObjectHandleCount@4
581 *
582 * DESCRIPTION
583 * Retrieves the handle count of the given object.
584 *
585 * ARGUMENTS
586 * ObjectBody = Body of the object.
587 *
588 * RETURN VALUE
589 * Reference count.
590 */
591 ULONG
592 ObGetObjectHandleCount(PVOID Object)
593 {
594 POBJECT_HEADER Header;
595
596 assert(Object);
597 Header = BODY_TO_HEADER(Object);
598
599 return(Header->HandleCount);
600 }
601
602 /* EOF */