| /* |
| * 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; |
| } |