/*++ Copyright (c) 1989-2000 Microsoft Corporation Module Name: obhandle.c Abstract: This module implements routines to manage object handles. --*/ #include "obp.h" VOID ObpDetachNamedObject( IN PVOID Object, IN KIRQL OldIrql ) /*++ Routine Description: This routine detaches a named object from its parent directory. Arguments: Object - Supplies the named object to remove. Return Value: None. --*/ { POBJECT_HEADER_NAME_INFO ObjectHeaderNameInfo; POBJECT_DIRECTORY Directory; OCHAR DriveLetter; ULONG HashIndex; POBJECT_HEADER_NAME_INFO LastObjectHeaderNameInfo; POBJECT_HEADER_NAME_INFO CurrentObjectHeaderNameInfo; ObpAssertObjectManagerLock(); ASSERT(ObpIsFlagSet(OBJECT_TO_OBJECT_HEADER(Object)->Flags, OB_FLAG_NAMED_OBJECT)); ASSERT(ObpIsFlagSet(OBJECT_TO_OBJECT_HEADER(Object)->Flags, OB_FLAG_ATTACHED_OBJECT)); ObjectHeaderNameInfo = OBJECT_TO_OBJECT_HEADER_NAME_INFO(Object); Directory = ObjectHeaderNameInfo->Directory; // // If we're removing a drive letter relative to the DOS devices directory, // then also remove the object from the quick array lookup. // if ((Directory == ObpDosDevicesDirectoryObject) && (ObjectHeaderNameInfo->Name.Length == sizeof(OCHAR) * 2) && (ObjectHeaderNameInfo->Name.Buffer[1] == (OCHAR)':')) { DriveLetter = ObjectHeaderNameInfo->Name.Buffer[0]; if (DriveLetter >= 'a' && DriveLetter <= 'z') { ASSERT(ObpDosDevicesDriveLetterMap[DriveLetter - 'a'] != NULL); ObpDosDevicesDriveLetterMap[DriveLetter - 'a'] = NULL; } else if (DriveLetter >= 'A' && DriveLetter <= 'Z') { ASSERT(ObpDosDevicesDriveLetterMap[DriveLetter - 'A'] != NULL); ObpDosDevicesDriveLetterMap[DriveLetter - 'A'] = NULL; } } // // Compute the hash index for the object's name. // HashIndex = ObpComputeHashIndex(&ObjectHeaderNameInfo->Name); // // Walk through the directory's hash table to find the object so that we // can detach it. // LastObjectHeaderNameInfo = NULL; CurrentObjectHeaderNameInfo = Directory->HashBuckets[HashIndex]; while (CurrentObjectHeaderNameInfo != ObjectHeaderNameInfo) { LastObjectHeaderNameInfo = CurrentObjectHeaderNameInfo; CurrentObjectHeaderNameInfo = CurrentObjectHeaderNameInfo->ChainLink; ASSERT(CurrentObjectHeaderNameInfo != NULL); } // // Remove the entry. // if (LastObjectHeaderNameInfo == NULL) { Directory->HashBuckets[HashIndex] = CurrentObjectHeaderNameInfo->ChainLink; } else { LastObjectHeaderNameInfo->ChainLink = CurrentObjectHeaderNameInfo->ChainLink; } // // Null out the link and directory fields so that we don't attempt to do // this again. // ObjectHeaderNameInfo->ChainLink = NULL; ObjectHeaderNameInfo->Directory = NULL; // // Release the reference to the directory and the object which applied in // ObInsertObject. // ObpReleaseObjectManagerLock(OldIrql); ObDereferenceObject(Directory); ObDereferenceObject(Object); } NTSTATUS NtClose( IN HANDLE Handle ) /*++ Routine Description: This routine closes the supplied handle. Arguments: Handle - Supplies the handle to close. Return Value: Status of operation. --*/ { NTSTATUS status; KIRQL OldIrql; PVOID Object; POBJECT_HEADER ObjectHeader; ULONG HandleCount; ObpAcquireObjectManagerLock(&OldIrql); // // Attempt to destroy the handle and obtain the object that was stored // in the handle. // Object = ObpDestroyObjectHandle(Handle); if (Object != NULL) { ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); // // Grab the current handle count for the object. // HandleCount = ObjectHeader->HandleCount; ASSERT(HandleCount > 0); // // Decrement the number of handles for this object. // ObjectHeader->HandleCount--; // // If the object type has a close procedure, invoke it with the old // handle count. // if (ObjectHeader->Type->CloseProcedure != NULL) { ObpReleaseObjectManagerLock(OldIrql); ObjectHeader->Type->CloseProcedure(Object, HandleCount); ObpAcquireObjectManagerLock(&OldIrql); } // // Check if the object should be removed from its parent directory. // if ((ObjectHeader->HandleCount == 0) && ObpIsFlagSet(ObjectHeader->Flags, OB_FLAG_ATTACHED_OBJECT) && ObpIsFlagClear(ObjectHeader->Flags, OB_FLAG_PERMANENT_OBJECT)) { ObpDetachNamedObject(Object, OldIrql); } else { ObpReleaseObjectManagerLock(OldIrql); } // // Release the reference that the handle held on the object. // ObDereferenceObject(Object); status = STATUS_SUCCESS; } else { ObpReleaseObjectManagerLock(OldIrql); status = STATUS_INVALID_HANDLE; } return status; } NTSTATUS NtDuplicateObject( IN HANDLE SourceHandle, OUT PHANDLE TargetHandle, IN ULONG Options ) /*++ Routine Description: This routine duplicates the supplied handle. Arguments: SourceHandle - Supplies the handle to duplicate. TargetHandle - Supplies the location to receive the duplicated handle. Options - Supplies options that control the duplication process. Return Value: Status of operation. --*/ { NTSTATUS status; PVOID Object; // // Obtain the object referenced by the handle. // status = ObReferenceObjectByHandle(SourceHandle, NULL, &Object); if (!NT_SUCCESS(status)) { *TargetHandle = NULL; return status; } // // Close the source handle if requested to. // if (ObpIsFlagSet(Options, DUPLICATE_CLOSE_SOURCE)) { NtClose(SourceHandle); } // // Create a handle for the object and release the reference we acquired // above. // status = ObOpenObjectByPointer(Object, OBJECT_TO_OBJECT_HEADER(Object)->Type, TargetHandle); ObDereferenceObject(Object); return status; } NTSTATUS NtMakeTemporaryObject( IN HANDLE Handle ) /*++ Routine Description: This routine converts a permanent object to a non permanent object. Non permanent objects are removed from the object directory when the last handle is closed. Arguments: Handle - Supplies the handle to make temporary. Return Value: Status of operation. --*/ { NTSTATUS status; PVOID Object; status = ObReferenceObjectByHandle(Handle, NULL, &Object); if (NT_SUCCESS(status)) { ObMakeTemporaryObject(Object); ObDereferenceObject(Object); } return status; } VOID ObMakeTemporaryObject ( IN PVOID Object ) /*++ Routine Description: This routine converts a permanent object to a non permanent object. Non permanent objects are removed from the object directory when the last handle is closed. Arguments: Object - Supplies the object to make temporary. Return Value: None. --*/ { KIRQL OldIrql; POBJECT_HEADER ObjectHeader; ObpAcquireObjectManagerLock(&OldIrql); // // Clear the permanent flag. // ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); ObjectHeader->Flags &= ~OB_FLAG_PERMANENT_OBJECT; // // Check if the object should be removed from its parent directory. // if ((ObjectHeader->HandleCount == 0) && ObpIsFlagSet(ObjectHeader->Flags, OB_FLAG_ATTACHED_OBJECT)) { ObpDetachNamedObject(Object, OldIrql); } else { ObpReleaseObjectManagerLock(OldIrql); } }