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)
12 /* INCLUDES *****************************************************************/
14 #define NTOS_MODE_KERNEL
17 #include <internal/ob.h>
18 #include <internal/ps.h>
19 #include <internal/id.h>
20 #include <internal/ke.h>
23 #include <internal/debug.h>
26 /* FUNCTIONS ************************************************************/
28 PVOID HEADER_TO_BODY(POBJECT_HEADER obj)
30 return(((void *)obj)+sizeof(OBJECT_HEADER)-sizeof(COMMON_BODY_HEADER));
34 POBJECT_HEADER BODY_TO_HEADER(PVOID body)
36 PCOMMON_BODY_HEADER chdr = (PCOMMON_BODY_HEADER)body;
37 return(CONTAINING_RECORD((&(chdr->Type)),OBJECT_HEADER,Type));
41 /**********************************************************************
51 VOID ObInitializeObject(POBJECT_HEADER ObjectHeader,
53 ACCESS_MASK DesiredAccess,
55 POBJECT_ATTRIBUTES ObjectAttributes)
57 ObjectHeader->HandleCount = 0;
58 ObjectHeader->RefCount = 1;
59 ObjectHeader->ObjectType = Type;
60 if (ObjectAttributes != NULL &&
61 ObjectAttributes->Attributes & OBJ_PERMANENT)
63 ObjectHeader->Permanent = TRUE;
67 ObjectHeader->Permanent = FALSE;
69 RtlInitUnicodeString(&(ObjectHeader->Name),NULL);
72 ObCreateHandle(PsGetCurrentProcess(),
73 HEADER_TO_BODY(ObjectHeader),
75 ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
81 /**********************************************************************
93 * Pointer to a unicode string that will contain the
94 * remaining path if the function returns successfully.
95 * The caller must free the buffer after use by calling
96 * RtlFreeUnicodeString ().
99 * Optional pointer to an object type. This is used to
100 * descide if a symbolic link object will be parsed or not.
105 ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
106 PVOID* ReturnedObject,
107 PUNICODE_STRING RemainingPath,
108 POBJECT_TYPE ObjectType)
113 POBJECT_HEADER CurrentHeader;
116 UNICODE_STRING PathString;
118 PUNICODE_STRING ObjectName;
120 DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
121 "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath);
122 DPRINT("ObjectAttributes->ObjectName %wZ\n",
123 ObjectAttributes->ObjectName);
125 RtlInitUnicodeString (RemainingPath, NULL);
127 if (ObjectAttributes->RootDirectory == NULL)
129 ObReferenceObjectByPointer(NameSpaceRoot,
133 CurrentObject = NameSpaceRoot;
137 Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
143 if (!NT_SUCCESS(Status))
149 ObjectName = ObjectAttributes->ObjectName;
150 if (ObjectName->Length == 0 ||
151 ObjectName->Buffer[0] == UNICODE_NULL)
153 *ReturnedObject = CurrentObject;
154 return STATUS_SUCCESS;
157 if (ObjectAttributes->RootDirectory == NULL &&
158 ObjectName->Buffer[0] != L'\\')
160 ObDereferenceObject (CurrentObject);
161 return STATUS_UNSUCCESSFUL;
164 /* Create a zero-terminated copy of the object name */
165 PathString.Length = ObjectName->Length;
166 PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR);
167 PathString.Buffer = ExAllocatePool (NonPagedPool,
168 PathString.MaximumLength);
169 if (PathString.Buffer == NULL)
171 ObDereferenceObject (CurrentObject);
172 return STATUS_INSUFFICIENT_RESOURCES;
175 RtlCopyMemory (PathString.Buffer,
178 PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL;
180 current = PathString.Buffer;
182 RootObject = CurrentObject;
183 Attributes = ObjectAttributes->Attributes;
184 if (ObjectType == ObSymbolicLinkType)
185 Attributes |= OBJ_OPENLINK;
189 DPRINT("current %S\n",current);
190 CurrentHeader = BODY_TO_HEADER(CurrentObject);
192 DPRINT("Current ObjectType %wZ\n",
193 &CurrentHeader->ObjectType->TypeName);
195 if (CurrentHeader->ObjectType->Parse == NULL)
197 DPRINT("Current object can't parse\n");
200 Status = CurrentHeader->ObjectType->Parse(CurrentObject,
205 if (Status == STATUS_REPARSE)
207 /* reparse the object path */
208 NextObject = RootObject;
209 current = PathString.Buffer;
211 ObReferenceObjectByPointer(NextObject,
217 if (NextObject == NULL)
221 ObDereferenceObject(CurrentObject);
222 CurrentObject = NextObject;
226 RtlCreateUnicodeString (RemainingPath, current);
227 RtlFreeUnicodeString (&PathString);
228 *ReturnedObject = CurrentObject;
230 return(STATUS_SUCCESS);
234 /**********************************************************************
236 * ObQueryNameString@16
247 ObQueryNameString (IN PVOID Object,
248 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
250 OUT PULONG ReturnLength)
252 POBJECT_NAME_INFORMATION LocalInfo;
253 POBJECT_HEADER ObjectHeader;
254 ULONG LocalReturnLength;
259 if (Length < sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR))
260 return STATUS_INVALID_BUFFER_SIZE;
262 ObjectNameInfo->Name.MaximumLength = Length - sizeof(OBJECT_NAME_INFORMATION);
263 ObjectNameInfo->Name.Length = 0;
264 ObjectNameInfo->Name.Buffer =
265 (PWCHAR)((ULONG_PTR)ObjectNameInfo + sizeof(OBJECT_NAME_INFORMATION));
266 ObjectNameInfo->Name.Buffer[0] = 0;
268 ObjectHeader = BODY_TO_HEADER(Object);
270 if (ObjectHeader->ObjectType != NULL &&
271 ObjectHeader->ObjectType->QueryName != NULL)
273 DPRINT ("Calling %x\n", ObjectHeader->ObjectType->QueryName);
274 Status = ObjectHeader->ObjectType->QueryName (Object,
279 else if (ObjectHeader->Name.Length > 0 && ObjectHeader->Name.Buffer != NULL)
281 DPRINT ("Object does not have a 'QueryName' function\n");
283 if (ObjectHeader->Parent == NameSpaceRoot)
285 DPRINT ("Reached the root directory\n");
286 ObjectNameInfo->Name.Length = 0;
287 ObjectNameInfo->Name.Buffer[0] = 0;
288 Status = STATUS_SUCCESS;
290 else if (ObjectHeader->Parent != NULL)
292 LocalInfo = ExAllocatePool (NonPagedPool,
293 sizeof(OBJECT_NAME_INFORMATION) +
294 MAX_PATH * sizeof(WCHAR));
295 if (LocalInfo == NULL)
296 return STATUS_INSUFFICIENT_RESOURCES;
298 Status = ObQueryNameString (ObjectHeader->Parent,
300 MAX_PATH * sizeof(WCHAR),
302 if (!NT_SUCCESS (Status))
304 ExFreePool (LocalInfo);
308 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
311 ExFreePool (LocalInfo);
313 if (!NT_SUCCESS (Status))
317 DPRINT ("Object path %wZ\n", &ObjectHeader->Name);
318 Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name,
320 if (!NT_SUCCESS (Status))
323 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
324 &ObjectHeader->Name);
328 DPRINT ("Object is unnamed\n");
330 ObjectNameInfo->Name.MaximumLength = 0;
331 ObjectNameInfo->Name.Length = 0;
332 ObjectNameInfo->Name.Buffer = NULL;
334 Status = STATUS_SUCCESS;
337 if (NT_SUCCESS (Status))
339 ObjectNameInfo->Name.MaximumLength =
340 (ObjectNameInfo->Name.Length) ? ObjectNameInfo->Name.Length + sizeof(WCHAR) : 0;
342 sizeof(OBJECT_NAME_INFORMATION) + ObjectNameInfo->Name.MaximumLength;
343 DPRINT ("Returned object path: %wZ\n", &ObjectNameInfo->Name);
350 /**********************************************************************
352 * ObRosCreateObject@20
359 * Internal ReactOS function
363 ObRosCreateObject (OUT PHANDLE Handle,
364 IN ACCESS_MASK DesiredAccess,
365 IN POBJECT_ATTRIBUTES ObjectAttributes,
366 IN POBJECT_TYPE Type,
370 UNICODE_STRING RemainingPath;
371 POBJECT_HEADER Header;
372 POBJECT_HEADER ParentHeader = NULL;
374 BOOLEAN ObjectAttached = FALSE;
377 assert_irql(APC_LEVEL);
379 DPRINT("ObRosCreateObject(Handle %x, ObjectAttributes %x, Type %x)\n",
380 Handle, ObjectAttributes, Type);
382 if (ObjectAttributes != NULL &&
383 ObjectAttributes->ObjectName != NULL &&
384 ObjectAttributes->ObjectName->Buffer != NULL)
386 Status = ObFindObject(ObjectAttributes,
390 if (!NT_SUCCESS(Status))
392 DPRINT("ObFindObject() failed! (Status 0x%x)\n", Status);
398 RtlInitUnicodeString(&RemainingPath, NULL);
401 RtlMapGenericMask(&DesiredAccess,
404 Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
405 OBJECT_ALLOC_SIZE(Type),
407 ObInitializeObject(Header,
415 ParentHeader = BODY_TO_HEADER(Parent);
418 if (ParentHeader != NULL &&
419 ParentHeader->ObjectType == ObDirectoryType &&
420 RemainingPath.Buffer != NULL)
422 NamePtr = RemainingPath.Buffer;
423 if (*NamePtr == L'\\')
426 ObpAddEntryDirectory(Parent,
430 ObjectAttached = TRUE;
433 if ((Header->ObjectType != NULL) &&
434 (Header->ObjectType->Create != NULL))
436 DPRINT("Calling %x\n", Header->ObjectType->Create);
437 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
439 RemainingPath.Buffer,
441 if (!NT_SUCCESS(Status))
443 if (ObjectAttached == TRUE)
445 ObpRemoveEntryDirectory(Header);
449 ObDereferenceObject(Parent);
451 RtlFreeUnicodeString(&Header->Name);
452 RtlFreeUnicodeString(&RemainingPath);
457 RtlFreeUnicodeString( &RemainingPath );
461 *Object = HEADER_TO_BODY(Header);
466 ObCreateHandle(PsGetCurrentProcess(),
469 ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT) ? TRUE : FALSE,
473 return(STATUS_SUCCESS);
476 /**********************************************************************
489 ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
490 IN POBJECT_TYPE ObjectType,
491 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
492 IN KPROCESSOR_MODE AccessMode,
493 IN OUT PVOID ParseContext OPTIONAL,
495 IN ULONG PagedPoolCharge OPTIONAL,
496 IN ULONG NonPagedPoolCharge OPTIONAL,
500 return STATUS_NOT_IMPLEMENTED;
507 ObReferenceObjectByPointer(IN PVOID Object,
508 IN ACCESS_MASK DesiredAccess,
509 IN POBJECT_TYPE ObjectType,
510 IN KPROCESSOR_MODE AccessMode)
512 * FUNCTION: Increments the pointer reference count for a given object
514 * ObjectBody = Object's body
515 * DesiredAccess = Desired access to the object
516 * ObjectType = Points to the object type structure
517 * AccessMode = Type of access check to perform
521 POBJECT_HEADER Header;
523 // DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
524 // Object,ObjectType);
526 Header = BODY_TO_HEADER(Object);
528 if (ObjectType != NULL && Header->ObjectType != ObjectType)
530 DPRINT("Failed %x (type was %x %S) should be %x %S\n",
533 Header->ObjectType->TypeName.Buffer,
535 ObjectType->TypeName.Buffer);
536 return(STATUS_UNSUCCESSFUL);
538 if (Header->ObjectType == PsProcessType)
540 DPRINT("Ref p 0x%x refcount %d type %x ",
541 Object, Header->RefCount, PsProcessType);
542 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
544 if (Header->ObjectType == PsThreadType)
546 DPRINT("Deref t 0x%x with refcount %d type %x ",
547 Object, Header->RefCount, PsThreadType);
548 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
551 if (Header->CloseInProcess)
553 return(STATUS_UNSUCCESSFUL);
556 InterlockedIncrement(&Header->RefCount);
558 return(STATUS_SUCCESS);
566 ObOpenObjectByPointer(IN POBJECT Object,
567 IN ULONG HandleAttributes,
568 IN PACCESS_STATE PassedAccessState,
569 IN ACCESS_MASK DesiredAccess,
570 IN POBJECT_TYPE ObjectType,
571 IN KPROCESSOR_MODE AccessMode,
576 DPRINT("ObOpenObjectByPointer()\n");
578 Status = ObReferenceObjectByPointer(Object,
582 if (!NT_SUCCESS(Status))
587 Status = ObCreateHandle(PsGetCurrentProcess(),
590 HandleAttributes & OBJ_INHERIT,
593 ObDereferenceObject(Object);
595 return STATUS_SUCCESS;
600 ObpPerformRetentionChecks(POBJECT_HEADER Header)
602 // DPRINT("ObPerformRetentionChecks(Header %x), RefCount %d, HandleCount %d\n",
603 // Header,Header->RefCount,Header->HandleCount);
605 if (Header->RefCount < 0)
607 CPRINT("Object %x/%x has invalid reference count (%d)\n",
608 Header, HEADER_TO_BODY(Header), Header->RefCount);
611 if (Header->HandleCount < 0)
613 CPRINT("Object %x/%x has invalid handle count (%d)\n",
614 Header, HEADER_TO_BODY(Header), Header->HandleCount);
618 if (Header->RefCount == 0 &&
619 Header->HandleCount == 0 &&
620 Header->Permanent == FALSE)
622 if (Header->CloseInProcess)
625 return STATUS_UNSUCCESSFUL;
627 Header->CloseInProcess = TRUE;
628 if (Header->ObjectType != NULL &&
629 Header->ObjectType->Delete != NULL)
631 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
633 if (Header->Name.Buffer != NULL)
635 ObpRemoveEntryDirectory(Header);
636 RtlFreeUnicodeString(&Header->Name);
638 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
641 return(STATUS_SUCCESS);
645 /**********************************************************************
647 * ObfReferenceObject@4
650 * Increments a given object's reference count and performs
654 * ObjectBody = Body of the object.
662 ObfReferenceObject(IN PVOID Object)
664 POBJECT_HEADER Header;
668 Header = BODY_TO_HEADER(Object);
670 if (Header->CloseInProcess)
674 InterlockedIncrement(&Header->RefCount);
676 ObpPerformRetentionChecks(Header);
680 /**********************************************************************
682 * ObfDereferenceObject@4
685 * Decrements a given object's reference count and performs
689 * ObjectBody = Body of the object.
697 ObfDereferenceObject(IN PVOID Object)
699 POBJECT_HEADER Header;
700 extern POBJECT_TYPE PsProcessType;
704 Header = BODY_TO_HEADER(Object);
706 if (Header->ObjectType == PsProcessType)
708 DPRINT("Deref p 0x%x with refcount %d type %x ",
709 Object, Header->RefCount, PsProcessType);
710 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
712 if (Header->ObjectType == PsThreadType)
714 DPRINT("Deref t 0x%x with refcount %d type %x ",
715 Object, Header->RefCount, PsThreadType);
716 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
719 InterlockedDecrement(&Header->RefCount);
721 ObpPerformRetentionChecks(Header);
725 /**********************************************************************
727 * ObGetObjectPointerCount@4
730 * Retrieves the pointer(reference) count of the given object.
733 * ObjectBody = Body of the object.
741 ObGetObjectPointerCount(PVOID Object)
743 POBJECT_HEADER Header;
746 Header = BODY_TO_HEADER(Object);
748 return(Header->RefCount);
752 /**********************************************************************
754 * ObGetObjectHandleCount@4
757 * Retrieves the handle count of the given object.
760 * ObjectBody = Body of the object.
766 ObGetObjectHandleCount(PVOID Object)
768 POBJECT_HEADER Header;
771 Header = BODY_TO_HEADER(Object);
773 return(Header->HandleCount);