/* * dlls/rsaenh/handle.c * Support code to manage HANDLE tables. * * Copyright 1998 Alexandre Julliard * Copyright 2002-2004 Mike McCormack for CodeWeavers * Copyright 2004 Michael Jung * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include <string.h> #include <stdarg.h> #include "windef.h" #include "winbase.h" #include "handle.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(handle); #define HANDLE2INDEX(h) ((h)-1) #define INDEX2HANDLE(i) ((i)+1) /****************************************************************************** * init_handle_table * * Initializes the HANDLETABLE structure pointed to by lpTable * * PARAMS * lpTable [I] Pointer to the HANDLETABLE structure, which is to be initialized. * * NOTES * You have to call destroy_handle_table when you don't need the table * any more. */ void init_handle_table(struct handle_table *lpTable) { TRACE("(lpTable=%p)\n", lpTable); lpTable->paEntries = NULL; lpTable->iEntries = 0; lpTable->iFirstFree = 0; InitializeCriticalSection(&lpTable->mutex); lpTable->mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": HANDLETABLE.mutex"); } /****************************************************************************** * destroy_handle_table * * Destroys the handle table. * * PARAMS * lpTable [I] Pointer to the handle table, which is to be destroyed. */ void destroy_handle_table(struct handle_table *lpTable) { TRACE("(lpTable=%p)\n", lpTable); HeapFree(GetProcessHeap(), 0, lpTable->paEntries); lpTable->mutex.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&lpTable->mutex); } /****************************************************************************** * is_valid_handle * * Tests if handle is valid given the specified handle table * * PARAMS * lpTable [I] Pointer to the handle table, with respect to which the handle's * validness is tested. * handle [I] The handle tested for validness. * dwType [I] A magic value that identifies the referenced object's type. * * RETURNS * TRUE, if handle is valid. * FALSE, if handle is not valid. */ BOOL is_valid_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType) { unsigned int index = HANDLE2INDEX(handle); BOOL ret = FALSE; TRACE("(lpTable=%p, handle=%ld)\n", lpTable, handle); EnterCriticalSection(&lpTable->mutex); /* We don't use zero handle values */ if (!handle) goto exit; /* Check for index out of table bounds */ if (index >= lpTable->iEntries) goto exit; /* Check if this handle is currently allocated */ if (!lpTable->paEntries[index].pObject) goto exit; /* Check if this handle references an object of the correct type. */ if (lpTable->paEntries[index].pObject->dwType != dwType) goto exit; ret = TRUE; exit: LeaveCriticalSection(&lpTable->mutex); return ret; } /****************************************************************************** * grow_handle_table [Internal] * * Grows the number of entries in the given table by TABLE_SIZE_INCREMENT * * PARAMS * lpTable [I] Pointer to the table, which is to be grown * * RETURNS * TRUE, if successful * FALSE, if not successful (out of memory on process heap) * * NOTES * This is a support function for alloc_handle. Do not call! */ static BOOL grow_handle_table(struct handle_table *lpTable) { struct handle_table_entry *newEntries; unsigned int i, newIEntries; newIEntries = lpTable->iEntries + TABLE_SIZE_INCREMENT; newEntries = HeapAlloc(GetProcessHeap(), 0, sizeof(struct handle_table_entry)*newIEntries); if (!newEntries) return FALSE; if (lpTable->paEntries) { memcpy(newEntries, lpTable->paEntries, sizeof(struct handle_table_entry)*lpTable->iEntries); HeapFree(GetProcessHeap(), 0, lpTable->paEntries); } for (i=lpTable->iEntries; i<newIEntries; i++) { newEntries[i].pObject = NULL; newEntries[i].iNextFree = i+1; } lpTable->paEntries = newEntries; lpTable->iEntries = newIEntries; return TRUE; } /****************************************************************************** * alloc_handle * * Allocates a new handle to the specified object in a given handle table. * * PARAMS * lpTable [I] Pointer to the handle table, from which the new handle is * allocated. * lpObject [I] Pointer to the object, for which a handle shall be allocated. * lpHandle [O] Pointer to a handle variable, into which the handle value will * be stored. If not successful, this will be * INVALID_HANDLE_VALUE * RETURNS * TRUE, if successful * FALSE, if not successful (no free handle) */ static BOOL alloc_handle(struct handle_table *lpTable, OBJECTHDR *lpObject, HCRYPTKEY *lpHandle) { BOOL ret = FALSE; TRACE("(lpTable=%p, lpObject=%p, lpHandle=%p)\n", lpTable, lpObject, lpHandle); EnterCriticalSection(&lpTable->mutex); if (lpTable->iFirstFree >= lpTable->iEntries) if (!grow_handle_table(lpTable)) { *lpHandle = (HCRYPTKEY)INVALID_HANDLE_VALUE; goto exit; } *lpHandle = INDEX2HANDLE(lpTable->iFirstFree); lpTable->paEntries[lpTable->iFirstFree].pObject = lpObject; lpTable->iFirstFree = lpTable->paEntries[lpTable->iFirstFree].iNextFree; InterlockedIncrement(&lpObject->refcount); ret = TRUE; exit: LeaveCriticalSection(&lpTable->mutex); return ret; } /****************************************************************************** * release_handle * * Releases resources occupied by the specified handle in the given table. * The reference count of the handled object is decremented. If it becomes * zero and if the 'destructor' function pointer member is non NULL, the * destructor function will be called. Note that release_handle does not * release resources other than the handle itself. If this is wanted, do it * in the destructor function. * * PARAMS * lpTable [I] Pointer to the handle table, from which a handle is to be * released. * handle [I] The handle, which is to be released * dwType [I] Identifier for the type of the object, for which a handle is * to be released. * * RETURNS * TRUE, if successful * FALSE, if not successful (invalid handle) */ BOOL release_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType) { unsigned int index = HANDLE2INDEX(handle); OBJECTHDR *pObject; BOOL ret = FALSE; TRACE("(lpTable=%p, handle=%ld)\n", lpTable, handle); EnterCriticalSection(&lpTable->mutex); if (!is_valid_handle(lpTable, handle, dwType)) goto exit; pObject = lpTable->paEntries[index].pObject; if (InterlockedDecrement(&pObject->refcount) == 0) { TRACE("destroying handle %ld\n", handle); if (pObject->destructor) pObject->destructor(pObject); } lpTable->paEntries[index].pObject = NULL; lpTable->paEntries[index].iNextFree = lpTable->iFirstFree; lpTable->iFirstFree = index; ret = TRUE; exit: LeaveCriticalSection(&lpTable->mutex); return ret; } /****************************************************************************** * lookup_handle * * Returns the object identified by the handle in the given handle table * * PARAMS * lpTable [I] Pointer to the handle table, in which the handle is looked up. * handle [I] The handle, which is to be looked up * lplpObject [O] Pointer to the variable, into which the pointer to the * object looked up is copied. * RETURNS * TRUE, if successful * FALSE, if not successful (invalid handle) */ BOOL lookup_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType, OBJECTHDR **lplpObject) { BOOL ret = FALSE; TRACE("(lpTable=%p, handle=%ld, lplpObject=%p)\n", lpTable, handle, lplpObject); EnterCriticalSection(&lpTable->mutex); if (!is_valid_handle(lpTable, handle, dwType)) { *lplpObject = NULL; goto exit; } *lplpObject = lpTable->paEntries[HANDLE2INDEX(handle)].pObject; ret = TRUE; exit: LeaveCriticalSection(&lpTable->mutex); return ret; } /****************************************************************************** * copy_handle * * Copies a handle. Increments the reference count of the object referenced * by the handle. * * PARAMS * lpTable [I] Pointer to the handle table, which holds the handle to be copied. * handle [I] The handle to be copied. * copy [O] Pointer to a handle variable, where the copied handle is put. * * RETURNS * TRUE, if successful * FALSE, if not successful (invalid handle or out of memory) */ BOOL copy_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType, HCRYPTKEY *copy) { OBJECTHDR *pObject; BOOL ret; TRACE("(lpTable=%p, handle=%ld, copy=%p)\n", lpTable, handle, copy); EnterCriticalSection(&lpTable->mutex); if (!lookup_handle(lpTable, handle, dwType, &pObject)) { *copy = (HCRYPTKEY)INVALID_HANDLE_VALUE; LeaveCriticalSection(&lpTable->mutex); return FALSE; } ret = alloc_handle(lpTable, pObject, copy); LeaveCriticalSection(&lpTable->mutex); return ret; } /****************************************************************************** * new_object * * Allocates a new object of size cbSize on the current process's heap. * Initializes the object header using the destructor and dwType params. * Allocates a handle to the object in the handle table pointed to by lpTable. * Returns a pointer to the created object in ppObject. * Returns a handle to the created object. * * PARAMS * lpTable [I] Pointer to the handle table, from which a handle is to be * allocated. * cbSize [I] Size of the object to be allocated in bytes. * dwType [I] Object type; will be copied to the object header. * destructor [I] Function pointer to a destructor function. Will be called * once the object's reference count gets zero. * ppObject [O] Pointer to a pointer variable, where a pointer to the newly * created object will be stored. You may set this to NULL. * * RETURNS * INVALID_HANDLE_VALUE, if something went wrong. * a handle to the new object, if successful. */ HCRYPTKEY new_object(struct handle_table *lpTable, size_t cbSize, DWORD dwType, DESTRUCTOR destructor, OBJECTHDR **ppObject) { OBJECTHDR *pObject; HCRYPTKEY hObject; if (ppObject) *ppObject = NULL; pObject = HeapAlloc(GetProcessHeap(), 0, cbSize); if (!pObject) return (HCRYPTKEY)INVALID_HANDLE_VALUE; pObject->dwType = dwType; pObject->refcount = 0; pObject->destructor = destructor; if (!alloc_handle(lpTable, pObject, &hObject)) HeapFree(GetProcessHeap(), 0, pObject); else if (ppObject) *ppObject = pObject; return hObject; }