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