10f8e25729e617696c88d478581c80ce6b3ab195
[reactos.git] / reactos / ntoskrnl / ob / object.c
1 /* $Id: object.c,v 1.83 2004/08/15 16:39:10 chorns 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 * PROGRAMMERS David Welch (welch@cwcom.net), Skywing (skywing@valhallalegends.com)
8 * UPDATE HISTORY:
9 * 10/06/98: Created
10 * 09/13/03: Fixed various ObXxx routines to not call retention
11 * checks directly at a raised IRQL.
12 */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <ntoskrnl.h>
17 #define NDEBUG
18 #include <internal/debug.h>
19
20
21 typedef struct _RETENTION_CHECK_PARAMS
22 {
23 WORK_QUEUE_ITEM WorkItem;
24 POBJECT_HEADER ObjectHeader;
25 } RETENTION_CHECK_PARAMS, *PRETENTION_CHECK_PARAMS;
26
27
28 /* FUNCTIONS ************************************************************/
29
30 PVOID HEADER_TO_BODY(POBJECT_HEADER obj)
31 {
32 return(((char*)obj)+sizeof(OBJECT_HEADER)-sizeof(COMMON_BODY_HEADER));
33 }
34
35
36 POBJECT_HEADER BODY_TO_HEADER(PVOID body)
37 {
38 PCOMMON_BODY_HEADER chdr = (PCOMMON_BODY_HEADER)body;
39 return(CONTAINING_RECORD((&(chdr->Type)),OBJECT_HEADER,Type));
40 }
41
42
43 /**********************************************************************
44 * NAME PRIVATE
45 * ObFindObject@16
46 *
47 * DESCRIPTION
48 *
49 * ARGUMENTS
50 * ObjectAttributes
51 *
52 * ReturnedObject
53 *
54 * RemainigPath
55 * Pointer to a unicode string that will contain the
56 * remaining path if the function returns successfully.
57 * The caller must free the buffer after use by calling
58 * RtlFreeUnicodeString ().
59 *
60 * ObjectType
61 * Optional pointer to an object type. This is used to
62 * descide if a symbolic link object will be parsed or not.
63 *
64 * RETURN VALUE
65 */
66 NTSTATUS
67 ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
68 PVOID* ReturnedObject,
69 PUNICODE_STRING RemainingPath,
70 POBJECT_TYPE ObjectType)
71 {
72 PVOID NextObject;
73 PVOID CurrentObject;
74 PVOID RootObject;
75 POBJECT_HEADER CurrentHeader;
76 NTSTATUS Status;
77 PWSTR current;
78 UNICODE_STRING PathString;
79 ULONG Attributes;
80 PUNICODE_STRING ObjectName;
81
82 DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
83 "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath);
84 DPRINT("ObjectAttributes->ObjectName %wZ\n",
85 ObjectAttributes->ObjectName);
86
87 RtlInitUnicodeString (RemainingPath, NULL);
88
89 if (ObjectAttributes->RootDirectory == NULL)
90 {
91 ObReferenceObjectByPointer(NameSpaceRoot,
92 DIRECTORY_TRAVERSE,
93 NULL,
94 UserMode);
95 CurrentObject = NameSpaceRoot;
96 }
97 else
98 {
99 Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
100 DIRECTORY_TRAVERSE,
101 NULL,
102 UserMode,
103 &CurrentObject,
104 NULL);
105 if (!NT_SUCCESS(Status))
106 {
107 return Status;
108 }
109 }
110
111 ObjectName = ObjectAttributes->ObjectName;
112 if (ObjectName->Length == 0 ||
113 ObjectName->Buffer[0] == UNICODE_NULL)
114 {
115 *ReturnedObject = CurrentObject;
116 return STATUS_SUCCESS;
117 }
118
119 if (ObjectAttributes->RootDirectory == NULL &&
120 ObjectName->Buffer[0] != L'\\')
121 {
122 ObDereferenceObject (CurrentObject);
123 return STATUS_UNSUCCESSFUL;
124 }
125
126 /* Create a zero-terminated copy of the object name */
127 PathString.Length = ObjectName->Length;
128 PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR);
129 PathString.Buffer = ExAllocatePool (NonPagedPool,
130 PathString.MaximumLength);
131 if (PathString.Buffer == NULL)
132 {
133 ObDereferenceObject (CurrentObject);
134 return STATUS_INSUFFICIENT_RESOURCES;
135 }
136
137 RtlCopyMemory (PathString.Buffer,
138 ObjectName->Buffer,
139 ObjectName->Length);
140 PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL;
141
142 current = PathString.Buffer;
143
144 RootObject = CurrentObject;
145 Attributes = ObjectAttributes->Attributes;
146 if (ObjectType == ObSymbolicLinkType)
147 Attributes |= OBJ_OPENLINK;
148
149 while (TRUE)
150 {
151 DPRINT("current %S\n",current);
152 CurrentHeader = BODY_TO_HEADER(CurrentObject);
153
154 DPRINT("Current ObjectType %wZ\n",
155 &CurrentHeader->ObjectType->TypeName);
156
157 if (CurrentHeader->ObjectType->Parse == NULL)
158 {
159 DPRINT("Current object can't parse\n");
160 break;
161 }
162 Status = CurrentHeader->ObjectType->Parse(CurrentObject,
163 &NextObject,
164 &PathString,
165 &current,
166 Attributes);
167 if (Status == STATUS_REPARSE)
168 {
169 /* reparse the object path */
170 NextObject = NameSpaceRoot;
171 current = PathString.Buffer;
172
173 ObReferenceObjectByPointer(NextObject,
174 DIRECTORY_TRAVERSE,
175 NULL,
176 UserMode);
177 }
178
179 if (NextObject == NULL)
180 {
181 break;
182 }
183 ObDereferenceObject(CurrentObject);
184 CurrentObject = NextObject;
185 }
186
187 if (current)
188 RtlCreateUnicodeString (RemainingPath, current);
189 RtlFreeUnicodeString (&PathString);
190 *ReturnedObject = CurrentObject;
191
192 return STATUS_SUCCESS;
193 }
194
195
196 /**********************************************************************
197 * NAME EXPORTED
198 * ObQueryNameString@16
199 *
200 * DESCRIPTION
201 *
202 * ARGUMENTS
203 *
204 * RETURN VALUE
205 *
206 * @implemented
207 */
208 NTSTATUS STDCALL
209 ObQueryNameString (IN PVOID Object,
210 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
211 IN ULONG Length,
212 OUT PULONG ReturnLength)
213 {
214 POBJECT_NAME_INFORMATION LocalInfo;
215 POBJECT_HEADER ObjectHeader;
216 ULONG LocalReturnLength;
217 NTSTATUS Status;
218
219 *ReturnLength = 0;
220
221 if (Length < sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR))
222 return STATUS_INVALID_BUFFER_SIZE;
223
224 ObjectNameInfo->Name.MaximumLength = (USHORT)(Length - sizeof(OBJECT_NAME_INFORMATION));
225 ObjectNameInfo->Name.Length = 0;
226 ObjectNameInfo->Name.Buffer =
227 (PWCHAR)((ULONG_PTR)ObjectNameInfo + sizeof(OBJECT_NAME_INFORMATION));
228 ObjectNameInfo->Name.Buffer[0] = 0;
229
230 ObjectHeader = BODY_TO_HEADER(Object);
231
232 if (ObjectHeader->ObjectType != NULL &&
233 ObjectHeader->ObjectType->QueryName != NULL)
234 {
235 DPRINT ("Calling %x\n", ObjectHeader->ObjectType->QueryName);
236 Status = ObjectHeader->ObjectType->QueryName (Object,
237 ObjectNameInfo,
238 Length,
239 ReturnLength);
240 }
241 else if (ObjectHeader->Name.Length > 0 && ObjectHeader->Name.Buffer != NULL)
242 {
243 DPRINT ("Object does not have a 'QueryName' function\n");
244
245 if (ObjectHeader->Parent == NameSpaceRoot)
246 {
247 DPRINT ("Reached the root directory\n");
248 ObjectNameInfo->Name.Length = 0;
249 ObjectNameInfo->Name.Buffer[0] = 0;
250 Status = STATUS_SUCCESS;
251 }
252 else if (ObjectHeader->Parent != NULL)
253 {
254 LocalInfo = ExAllocatePool (NonPagedPool,
255 sizeof(OBJECT_NAME_INFORMATION) +
256 MAX_PATH * sizeof(WCHAR));
257 if (LocalInfo == NULL)
258 return STATUS_INSUFFICIENT_RESOURCES;
259
260 Status = ObQueryNameString (ObjectHeader->Parent,
261 LocalInfo,
262 MAX_PATH * sizeof(WCHAR),
263 &LocalReturnLength);
264 if (!NT_SUCCESS (Status))
265 {
266 ExFreePool (LocalInfo);
267 return Status;
268 }
269
270 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
271 &LocalInfo->Name);
272
273 ExFreePool (LocalInfo);
274
275 if (!NT_SUCCESS (Status))
276 return Status;
277 }
278
279 DPRINT ("Object path %wZ\n", &ObjectHeader->Name);
280 Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name,
281 L"\\");
282 if (!NT_SUCCESS (Status))
283 return Status;
284
285 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
286 &ObjectHeader->Name);
287 }
288 else
289 {
290 DPRINT ("Object is unnamed\n");
291
292 ObjectNameInfo->Name.MaximumLength = 0;
293 ObjectNameInfo->Name.Length = 0;
294 ObjectNameInfo->Name.Buffer = NULL;
295
296 Status = STATUS_SUCCESS;
297 }
298
299 if (NT_SUCCESS (Status))
300 {
301 ObjectNameInfo->Name.MaximumLength =
302 (ObjectNameInfo->Name.Length) ? ObjectNameInfo->Name.Length + sizeof(WCHAR) : 0;
303 *ReturnLength =
304 sizeof(OBJECT_NAME_INFORMATION) + ObjectNameInfo->Name.MaximumLength;
305 DPRINT ("Returned object path: %wZ\n", &ObjectNameInfo->Name);
306 }
307
308 return Status;
309 }
310
311
312 /**********************************************************************
313 * NAME EXPORTED
314 * ObCreateObject@36
315 *
316 * DESCRIPTION
317 *
318 * ARGUMENTS
319 *
320 * RETURN VALUE
321 * Status
322 *
323 * @implemented
324 */
325 NTSTATUS STDCALL
326 ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
327 IN POBJECT_TYPE Type,
328 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
329 IN KPROCESSOR_MODE AccessMode,
330 IN OUT PVOID ParseContext OPTIONAL,
331 IN ULONG ObjectSize,
332 IN ULONG PagedPoolCharge OPTIONAL,
333 IN ULONG NonPagedPoolCharge OPTIONAL,
334 OUT PVOID *Object)
335 {
336 PVOID Parent = NULL;
337 UNICODE_STRING RemainingPath;
338 POBJECT_HEADER Header;
339 POBJECT_HEADER ParentHeader = NULL;
340 NTSTATUS Status;
341 BOOLEAN ObjectAttached = FALSE;
342 PWCHAR NamePtr;
343 PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL;
344 SECURITY_SUBJECT_CONTEXT SubjectContext;
345
346 assert_irql(APC_LEVEL);
347
348 DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
349 Type, ObjectAttributes, Object);
350
351 if (Type == NULL)
352 {
353 DPRINT1("Invalid object type!\n");
354 return STATUS_INVALID_PARAMETER;
355 }
356
357 if (ObjectAttributes != NULL &&
358 ObjectAttributes->ObjectName != NULL &&
359 ObjectAttributes->ObjectName->Buffer != NULL)
360 {
361 Status = ObFindObject(ObjectAttributes,
362 &Parent,
363 &RemainingPath,
364 NULL);
365 if (!NT_SUCCESS(Status))
366 {
367 DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status);
368 return Status;
369 }
370 }
371 else
372 {
373 RtlInitUnicodeString(&RemainingPath, NULL);
374 }
375
376 Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
377 OBJECT_ALLOC_SIZE(ObjectSize),
378 Type->Tag);
379 if (Header == NULL)
380 return STATUS_INSUFFICIENT_RESOURCES;
381 RtlZeroMemory(Header, OBJECT_ALLOC_SIZE(ObjectSize));
382
383 /* Initialize the object header */
384 Header->HandleCount = 0;
385 Header->RefCount = 1;
386 Header->ObjectType = Type;
387 if (ObjectAttributes != NULL &&
388 ObjectAttributes->Attributes & OBJ_PERMANENT)
389 {
390 Header->Permanent = TRUE;
391 }
392 else
393 {
394 Header->Permanent = FALSE;
395 }
396
397 if (ObjectAttributes != NULL &&
398 ObjectAttributes->Attributes & OBJ_INHERIT)
399 {
400 Header->Inherit = TRUE;
401 }
402 else
403 {
404 Header->Inherit = FALSE;
405 }
406
407 RtlInitUnicodeString(&(Header->Name),NULL);
408
409 if (Parent != NULL)
410 {
411 ParentHeader = BODY_TO_HEADER(Parent);
412 }
413
414 if (ParentHeader != NULL &&
415 ParentHeader->ObjectType == ObDirectoryType &&
416 RemainingPath.Buffer != NULL)
417 {
418 NamePtr = RemainingPath.Buffer;
419 if (*NamePtr == L'\\')
420 NamePtr++;
421
422 ObpAddEntryDirectory(Parent,
423 Header,
424 NamePtr);
425
426 ObjectAttached = TRUE;
427 }
428
429 if (Header->ObjectType->Create != NULL)
430 {
431 DPRINT("Calling %x\n", Header->ObjectType->Create);
432 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
433 Parent,
434 RemainingPath.Buffer,
435 ObjectAttributes);
436 if (!NT_SUCCESS(Status))
437 {
438 if (ObjectAttached == TRUE)
439 {
440 ObpRemoveEntryDirectory(Header);
441 }
442 if (Parent)
443 {
444 ObDereferenceObject(Parent);
445 }
446 RtlFreeUnicodeString(&Header->Name);
447 RtlFreeUnicodeString(&RemainingPath);
448 ExFreePool(Header);
449 return Status;
450 }
451 }
452 RtlFreeUnicodeString(&RemainingPath);
453
454 SeCaptureSubjectContext(&SubjectContext);
455
456 /* Build the new security descriptor */
457 Status = SeAssignSecurity((ParentHeader != NULL) ? ParentHeader->SecurityDescriptor : NULL,
458 (ObjectAttributes != NULL) ? ObjectAttributes->SecurityDescriptor : NULL,
459 &NewSecurityDescriptor,
460 (Header->ObjectType == ObDirectoryType),
461 &SubjectContext,
462 Header->ObjectType->Mapping,
463 PagedPool);
464 if (NT_SUCCESS(Status))
465 {
466 DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor);
467
468 if (Header->ObjectType->Security != NULL)
469 {
470 /* Call the security method */
471 Status = Header->ObjectType->Security(HEADER_TO_BODY(Header),
472 AssignSecurityDescriptor,
473 0,
474 NewSecurityDescriptor,
475 NULL);
476 }
477 else
478 {
479 /* Assign the security descriptor to the object header */
480 Status = ObpAddSecurityDescriptor(NewSecurityDescriptor,
481 &Header->SecurityDescriptor);
482 DPRINT("Object security descriptor %p\n", Header->SecurityDescriptor);
483 }
484
485 /* Release the new security descriptor */
486 SeDeassignSecurity(&NewSecurityDescriptor);
487 }
488
489 SeReleaseSubjectContext(&SubjectContext);
490
491 if (Object != NULL)
492 {
493 *Object = HEADER_TO_BODY(Header);
494 }
495
496 return STATUS_SUCCESS;
497 }
498
499
500 /*
501 * FUNCTION: Increments the pointer reference count for a given object
502 * ARGUMENTS:
503 * ObjectBody = Object's body
504 * DesiredAccess = Desired access to the object
505 * ObjectType = Points to the object type structure
506 * AccessMode = Type of access check to perform
507 * RETURNS: Status
508 *
509 * @implemented
510 */
511 NTSTATUS STDCALL
512 ObReferenceObjectByPointer(IN PVOID Object,
513 IN ACCESS_MASK DesiredAccess,
514 IN POBJECT_TYPE ObjectType,
515 IN KPROCESSOR_MODE AccessMode)
516 {
517 POBJECT_HEADER Header;
518
519 DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
520 Object,ObjectType);
521
522 Header = BODY_TO_HEADER(Object);
523
524 if (ObjectType != NULL && Header->ObjectType != ObjectType)
525 {
526 DPRINT("Failed %x (type was %x %S) should be %x %S\n",
527 Header,
528 Header->ObjectType,
529 Header->ObjectType->TypeName.Buffer,
530 ObjectType,
531 ObjectType->TypeName.Buffer);
532 return(STATUS_UNSUCCESSFUL);
533 }
534 if (Header->ObjectType == PsProcessType)
535 {
536 DPRINT("Ref p 0x%x 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 if (Header->CloseInProcess)
548 {
549 if (Header->ObjectType == PsProcessType)
550 {
551 return STATUS_PROCESS_IS_TERMINATING;
552 }
553 if (Header->ObjectType == PsThreadType)
554 {
555 return STATUS_THREAD_IS_TERMINATING;
556 }
557 return(STATUS_UNSUCCESSFUL);
558 }
559
560 InterlockedIncrement(&Header->RefCount);
561
562 return(STATUS_SUCCESS);
563 }
564
565
566 /*
567 * @implemented
568 */
569 NTSTATUS STDCALL
570 ObOpenObjectByPointer(IN POBJECT Object,
571 IN ULONG HandleAttributes,
572 IN PACCESS_STATE PassedAccessState,
573 IN ACCESS_MASK DesiredAccess,
574 IN POBJECT_TYPE ObjectType,
575 IN KPROCESSOR_MODE AccessMode,
576 OUT PHANDLE Handle)
577 {
578 NTSTATUS Status;
579
580 DPRINT("ObOpenObjectByPointer()\n");
581
582 Status = ObReferenceObjectByPointer(Object,
583 0,
584 ObjectType,
585 AccessMode);
586 if (!NT_SUCCESS(Status))
587 {
588 return Status;
589 }
590
591 Status = ObCreateHandle(PsGetCurrentProcess(),
592 Object,
593 DesiredAccess,
594 (BOOLEAN)(HandleAttributes & OBJ_INHERIT),
595 Handle);
596
597 ObDereferenceObject(Object);
598
599 return STATUS_SUCCESS;
600 }
601
602
603 static NTSTATUS
604 ObpDeleteObject(POBJECT_HEADER Header)
605 {
606 DPRINT("ObPerformRetentionChecks(Header %p)\n", Header);
607 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
608 {
609 DPRINT("ObpPerformRetentionChecks called at an unsupported IRQL. Use ObpPerformRetentionChecksDpcLevel instead.\n");
610 KEBUGCHECK(0);
611 }
612
613 if (Header->SecurityDescriptor != NULL)
614 {
615 ObpRemoveSecurityDescriptor(Header->SecurityDescriptor);
616 }
617
618 if (Header->ObjectType != NULL &&
619 Header->ObjectType->Delete != NULL)
620 {
621 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
622 }
623
624 if (Header->Name.Buffer != NULL)
625 {
626 ObpRemoveEntryDirectory(Header);
627 RtlFreeUnicodeString(&Header->Name);
628 }
629
630 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
631 ExFreePool(Header);
632
633 return(STATUS_SUCCESS);
634 }
635
636
637 VOID STDCALL
638 ObpDeleteObjectWorkRoutine (IN PVOID Parameter)
639 {
640 PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter;
641 /* ULONG Tag; */ /* See below */
642
643 assert(Params);
644 assert(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */
645
646 /* Turn this on when we have ExFreePoolWithTag
647 Tag = Params->ObjectHeader->ObjectType->Tag; */
648 ObpDeleteObject(Params->ObjectHeader);
649 ExFreePool(Params);
650 /* ExFreePoolWithTag(Params, Tag); */
651 }
652
653
654 STATIC NTSTATUS
655 ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader,
656 IN LONG OldRefCount)
657 {
658 if (ObjectHeader->RefCount < 0)
659 {
660 CPRINT("Object %p/%p has invalid reference count (%d)\n",
661 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
662 ObjectHeader->RefCount);
663 KEBUGCHECK(0);
664 }
665
666 if (ObjectHeader->HandleCount < 0)
667 {
668 CPRINT("Object %p/%p has invalid handle count (%d)\n",
669 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
670 ObjectHeader->HandleCount);
671 KEBUGCHECK(0);
672 }
673
674 if (ObjectHeader->CloseInProcess)
675 {
676 KEBUGCHECK(0);
677 return STATUS_UNSUCCESSFUL;
678 }
679 ObjectHeader->CloseInProcess = TRUE;
680
681 switch (KeGetCurrentIrql ())
682 {
683 case PASSIVE_LEVEL:
684 return ObpDeleteObject (ObjectHeader);
685
686 case APC_LEVEL:
687 case DISPATCH_LEVEL:
688 {
689 PRETENTION_CHECK_PARAMS Params;
690
691 /*
692 We use must succeed pool here because if the allocation fails
693 then we leak memory.
694 */
695 Params = (PRETENTION_CHECK_PARAMS)
696 ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
697 sizeof(RETENTION_CHECK_PARAMS),
698 ObjectHeader->ObjectType->Tag);
699 Params->ObjectHeader = ObjectHeader;
700 ExInitializeWorkItem(&Params->WorkItem,
701 ObpDeleteObjectWorkRoutine,
702 (PVOID)Params);
703 ExQueueWorkItem(&Params->WorkItem,
704 CriticalWorkQueue);
705 }
706 return STATUS_PENDING;
707
708 default:
709 DPRINT("ObpPerformRetentionChecksDpcLevel called at unsupported "
710 "IRQL %u!\n", KeGetCurrentIrql());
711 KEBUGCHECK(0);
712 return STATUS_UNSUCCESSFUL;
713 }
714
715 return STATUS_SUCCESS;
716 }
717
718
719 /**********************************************************************
720 * NAME EXPORTED
721 * ObfReferenceObject@4
722 *
723 * DESCRIPTION
724 * Increments a given object's reference count and performs
725 * retention checks.
726 *
727 * ARGUMENTS
728 * ObjectBody = Body of the object.
729 *
730 * RETURN VALUE
731 * None.
732 *
733 * @implemented
734 */
735 VOID FASTCALL
736 ObfReferenceObject(IN PVOID Object)
737 {
738 POBJECT_HEADER Header;
739
740 assert(Object);
741
742 Header = BODY_TO_HEADER(Object);
743
744 /* No one should be referencing an object once we are deleting it. */
745 if (Header->CloseInProcess)
746 {
747 KEBUGCHECK(0);
748 }
749
750 (VOID)InterlockedIncrement(&Header->RefCount);
751 }
752
753
754 /**********************************************************************
755 * NAME EXPORTED
756 * ObfDereferenceObject@4
757 *
758 * DESCRIPTION
759 * Decrements a given object's reference count and performs
760 * retention checks.
761 *
762 * ARGUMENTS
763 * ObjectBody = Body of the object.
764 *
765 * RETURN VALUE
766 * None.
767 *
768 * @implemented
769 */
770 VOID FASTCALL
771 ObfDereferenceObject(IN PVOID Object)
772 {
773 POBJECT_HEADER Header;
774 LONG NewRefCount;
775 BOOL Permanent;
776 ULONG HandleCount;
777
778 assert(Object);
779
780 /* Extract the object header. */
781 Header = BODY_TO_HEADER(Object);
782 Permanent = Header->Permanent;
783 HandleCount = Header->HandleCount;
784
785 /*
786 Drop our reference and get the new count so we can tell if this was the
787 last reference.
788 */
789 NewRefCount = InterlockedDecrement(&Header->RefCount);
790 assert(NewRefCount >= 0);
791
792 /* Check whether the object can now be deleted. */
793 if (NewRefCount == 0 &&
794 HandleCount == 0 &&
795 !Permanent)
796 {
797 ObpDeleteObjectDpcLevel(Header, NewRefCount);
798 }
799 }
800
801
802 /**********************************************************************
803 * NAME EXPORTED
804 * ObGetObjectPointerCount@4
805 *
806 * DESCRIPTION
807 * Retrieves the pointer(reference) count of the given object.
808 *
809 * ARGUMENTS
810 * ObjectBody = Body of the object.
811 *
812 * RETURN VALUE
813 * Reference count.
814 *
815 * @implemented
816 */
817 ULONG STDCALL
818 ObGetObjectPointerCount(PVOID Object)
819 {
820 POBJECT_HEADER Header;
821
822 assert(Object);
823 Header = BODY_TO_HEADER(Object);
824
825 return(Header->RefCount);
826 }
827
828
829 /**********************************************************************
830 * NAME INTERNAL
831 * ObGetObjectHandleCount@4
832 *
833 * DESCRIPTION
834 * Retrieves the handle count of the given object.
835 *
836 * ARGUMENTS
837 * ObjectBody = Body of the object.
838 *
839 * RETURN VALUE
840 * Reference count.
841 */
842 ULONG
843 ObGetObjectHandleCount(PVOID Object)
844 {
845 POBJECT_HEADER Header;
846
847 assert(Object);
848 Header = BODY_TO_HEADER(Object);
849
850 return(Header->HandleCount);
851 }
852
853
854 /**********************************************************************
855 * NAME EXPORTED
856 * ObDereferenceObject@4
857 *
858 * DESCRIPTION
859 * Decrements a given object's reference count and performs
860 * retention checks.
861 *
862 * ARGUMENTS
863 * ObjectBody = Body of the object.
864 *
865 * RETURN VALUE
866 * None.
867 *
868 * @implemented
869 */
870
871 #ifdef ObDereferenceObject
872 #undef ObDereferenceObject
873 #endif
874
875 VOID STDCALL
876 ObDereferenceObject(IN PVOID Object)
877 {
878 ObfDereferenceObject(Object);
879 }
880
881 /* EOF */