kernel32: Add more tests for getting/setting a named pipe's state.
[wine] / dlls / rsaenh / handle.c
1 /*
2  * dlls/rsaenh/handle.c
3  * Support code to manage HANDLE tables.
4  *
5  * Copyright 1998 Alexandre Julliard
6  * Copyright 2002-2004 Mike McCormack for CodeWeavers
7  * Copyright 2004 Michael Jung
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include <string.h>
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "handle.h"
30
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(handle);
34
35 #define HANDLE2INDEX(h) ((h)-1)
36 #define INDEX2HANDLE(i) ((i)+1)
37
38 /******************************************************************************
39  *  init_handle_table
40  *
41  * Initializes the HANDLETABLE structure pointed to by lpTable
42  *
43  * PARAMS
44  *  lpTable [I] Pointer to the HANDLETABLE structure, which is to be initalized.
45  *
46  * NOTES
47  *  You have to call destroy_handle_table when you don't need the table
48  *  any more.
49  */
50 void init_handle_table(struct handle_table *lpTable)
51 {
52     TRACE("(lpTable=%p)\n", lpTable);
53         
54     lpTable->paEntries = NULL;
55     lpTable->iEntries = 0;
56     lpTable->iFirstFree = 0;
57     InitializeCriticalSection(&lpTable->mutex);
58     lpTable->mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": HANDLETABLE.mutex");
59 }
60
61 /******************************************************************************
62  *  destroy_handle_table
63  *
64  * Destroys the handle table.
65  * 
66  * PARAMS
67  *  lpTable [I] Pointer to the handle table, which is to be destroyed.
68  */
69 void destroy_handle_table(struct handle_table *lpTable)
70 {
71     TRACE("(lpTable=%p)\n", lpTable);
72         
73     HeapFree(GetProcessHeap(), 0, lpTable->paEntries);
74     lpTable->mutex.DebugInfo->Spare[0] = 0;
75     DeleteCriticalSection(&lpTable->mutex);
76 }
77
78 /******************************************************************************
79  *  is_valid_handle
80  *
81  * Tests if handle is valid given the specified handle table
82  * 
83  * PARAMS
84  *  lpTable [I] Pointer to the handle table, with respect to which the handle's 
85  *              validness is tested.
86  *  handle  [I] The handle tested for validness.
87  *  dwType  [I] A magic value that identifies the referenced object's type.
88  *
89  * RETURNS
90  *  non zero,  if handle is valid.
91  *  zero,      if handle is not valid.
92  */
93 int is_valid_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType)
94 {
95     unsigned int index = HANDLE2INDEX(handle);
96     int ret = 0;
97
98     TRACE("(lpTable=%p, handle=%ld)\n", lpTable, handle);
99     
100     EnterCriticalSection(&lpTable->mutex);
101         
102     /* We don't use zero handle values */
103     if (!handle) goto exit;
104  
105     /* Check for index out of table bounds */    
106     if (index >= lpTable->iEntries) goto exit;
107     
108     /* Check if this handle is currently allocated */
109     if (!lpTable->paEntries[index].pObject) goto exit;
110     
111     /* Check if this handle references an object of the correct type. */
112     if (lpTable->paEntries[index].pObject->dwType != dwType) goto exit;
113     
114     ret = 1;
115 exit:
116     LeaveCriticalSection(&lpTable->mutex);
117     return ret;
118 }
119
120 /******************************************************************************
121  *  grow_handle_table [Internal]
122  *
123  * Grows the number of entries in the given table by TABLE_SIZE_INCREMENT
124  *
125  * PARAMS 
126  *  lpTable [I] Pointer to the table, which is to be grown
127  *
128  * RETURNS
129  *  non zero,  if successful
130  *  zero,      if not successful (out of memory on process heap)
131  *
132  * NOTES
133  *  This is a support function for alloc_handle. Do not call!
134  */
135 static int grow_handle_table(struct handle_table *lpTable) 
136 {
137     struct handle_table_entry *newEntries;
138     unsigned int i, newIEntries;
139
140     newIEntries = lpTable->iEntries + TABLE_SIZE_INCREMENT;
141
142     newEntries = HeapAlloc(GetProcessHeap(), 0, sizeof(struct handle_table_entry)*newIEntries);
143     if (!newEntries) 
144         return 0;
145
146     if (lpTable->paEntries)
147     {
148         memcpy(newEntries, lpTable->paEntries, sizeof(struct handle_table_entry)*lpTable->iEntries);
149         HeapFree(GetProcessHeap(), 0, lpTable->paEntries);
150     }
151
152     for (i=lpTable->iEntries; i<newIEntries; i++)
153     {
154         newEntries[i].pObject = NULL;
155         newEntries[i].iNextFree = i+1;
156     }
157
158     lpTable->paEntries = newEntries;
159     lpTable->iEntries = newIEntries;
160
161     return 1;
162 }
163
164 /******************************************************************************
165  *  alloc_handle
166  *
167  * Allocates a new handle to the specified object in a given handle table.
168  *
169  * PARAMS
170  *  lpTable  [I] Pointer to the handle table, from which the new handle is 
171  *               allocated.
172  *  lpObject [I] Pointer to the object, for which a handle shall be allocated.
173  *  lpHandle [O] Pointer to a handle variable, into which the handle value will
174  *               be stored. If not successful, this will be 
175  *               INVALID_HANDLE_VALUE
176  * RETURNS
177  *  non zero,  if successful
178  *  zero,      if not successful (no free handle)
179  */
180 static int alloc_handle(struct handle_table *lpTable, OBJECTHDR *lpObject, HCRYPTKEY *lpHandle)
181 {
182     int ret = 0;
183
184     TRACE("(lpTable=%p, lpObject=%p, lpHandle=%p)\n", lpTable, lpObject, lpHandle);
185         
186     EnterCriticalSection(&lpTable->mutex);
187     if (lpTable->iFirstFree >= lpTable->iEntries) 
188         if (!grow_handle_table(lpTable))
189         {
190             *lpHandle = (HCRYPTKEY)INVALID_HANDLE_VALUE;
191             goto exit;
192         }
193
194     *lpHandle = INDEX2HANDLE(lpTable->iFirstFree);
195     
196     lpTable->paEntries[lpTable->iFirstFree].pObject = lpObject;
197     lpTable->iFirstFree = lpTable->paEntries[lpTable->iFirstFree].iNextFree;
198     InterlockedIncrement(&lpObject->refcount);
199
200     ret = 1;
201 exit:
202     LeaveCriticalSection(&lpTable->mutex);
203     return ret;
204 }
205
206 /******************************************************************************
207  *  release_handle
208  *
209  * Releases resources occupied by the specified handle in the given table.
210  * The reference count of the handled object is decremented. If it becomes
211  * zero and if the 'destructor' function pointer member is non NULL, the
212  * destructor function will be called. Note that release_handle does not 
213  * release resources other than the handle itself. If this is wanted, do it
214  * in the destructor function.
215  *
216  * PARAMS
217  *  lpTable [I] Pointer to the handle table, from which a handle is to be 
218  *              released.
219  *  handle  [I] The handle, which is to be released
220  *  dwType  [I] Identifier for the type of the object, for which a handle is
221  *              to be released.
222  *
223  * RETURNS
224  *  non zero,  if successful
225  *  zero,      if not successful (invalid handle)
226  */
227 int release_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType)
228 {
229     unsigned int index = HANDLE2INDEX(handle);
230     OBJECTHDR *pObject;
231     int ret = 0;
232
233     TRACE("(lpTable=%p, handle=%ld)\n", lpTable, handle);
234     
235     EnterCriticalSection(&lpTable->mutex);
236     
237     if (!is_valid_handle(lpTable, handle, dwType))
238         goto exit;
239
240     pObject = lpTable->paEntries[index].pObject;
241     if (InterlockedDecrement(&pObject->refcount) == 0)
242     {
243         TRACE("destroying handle %ld\n", handle);
244         if (pObject->destructor)
245             pObject->destructor(pObject);
246     }
247
248     lpTable->paEntries[index].pObject = NULL;
249     lpTable->paEntries[index].iNextFree = lpTable->iFirstFree;
250     lpTable->iFirstFree = index;
251    
252     ret = 1;
253 exit:
254     LeaveCriticalSection(&lpTable->mutex);
255     return ret;
256 }
257
258 /******************************************************************************
259  *  lookup_handle
260  *
261  * Returns the object identified by the handle in the given handle table
262  *
263  * PARAMS
264  *  lpTable    [I] Pointer to the handle table, in which the handle is looked up.
265  *  handle     [I] The handle, which is to be looked up
266  *    lplpObject [O] Pointer to the variable, into which the pointer to the 
267  *                   object looked up is copied.
268  * RETURNS
269  *  non zero,  if successful
270  *  zero,      if not successful (invalid handle)
271  */
272 int lookup_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType, OBJECTHDR **lplpObject)
273 {
274     int ret = 0;
275     
276     TRACE("(lpTable=%p, handle=%ld, lplpObject=%p)\n", lpTable, handle, lplpObject);
277     
278     EnterCriticalSection(&lpTable->mutex);
279     if (!is_valid_handle(lpTable, handle, dwType)) 
280     {
281         *lplpObject = NULL;
282         goto exit;
283     }
284     *lplpObject = lpTable->paEntries[HANDLE2INDEX(handle)].pObject;
285
286     ret = 1;
287 exit:
288     LeaveCriticalSection(&lpTable->mutex);
289     return ret;
290 }
291
292 /******************************************************************************
293  *  copy_handle
294  *
295  * Copies a handle. Increments the reference count of the object referenced
296  * by the handle.
297  *
298  * PARAMS
299  *  lpTable [I] Pointer to the handle table, which holds the handle to be copied.
300  *  handle  [I] The handle to be copied.
301  *  copy    [O] Pointer to a handle variable, where the copied handle is put.
302  *
303  * RETURNS
304  *  non zero,  if successful
305  *  zero,      if not successful (invalid handle or out of memory)
306  */
307 int copy_handle(struct handle_table *lpTable, HCRYPTKEY handle, DWORD dwType, HCRYPTKEY *copy)
308 {
309     OBJECTHDR *pObject;
310     int ret;
311         
312     TRACE("(lpTable=%p, handle=%ld, copy=%p)\n", lpTable, handle, copy);
313
314     EnterCriticalSection(&lpTable->mutex);
315     if (!lookup_handle(lpTable, handle, dwType, &pObject)) 
316     {
317         *copy = (HCRYPTKEY)INVALID_HANDLE_VALUE;
318         LeaveCriticalSection(&lpTable->mutex);
319         return 0;
320     }
321
322     ret = alloc_handle(lpTable, pObject, copy);
323     LeaveCriticalSection(&lpTable->mutex);
324     return ret;
325 }
326
327 /******************************************************************************
328  *  new_object
329  *
330  * Allocates a new object of size cbSize on the current process's heap.
331  * Initializes the object header using the destructor and dwType params.
332  * Allocates a handle to the object in the handle table pointed to by lpTable.
333  * Returns a pointer to the created object in ppObject.
334  * Returns a handle to the created object.
335  *
336  * PARAMS
337  *  lpTable    [I] Pointer to the handle table, from which a handle is to be 
338  *              allocated.
339  *  cbSize     [I] Size of the object to be allocated in bytes.
340  *  dwType     [I] Object type; will be copied to the object header.
341  *  destructor [I] Function pointer to a destructor function. Will be called
342  *                 once the object's reference count gets zero.
343  *  ppObject   [O] Pointer to a pointer variable, where a pointer to the newly
344  *                 created object will be stored. You may set this to NULL.
345  *
346  * RETURNS
347  *  INVALID_HANDLE_VALUE,        if something went wrong.
348  *  a handle to the new object,  if successful. 
349  */
350 HCRYPTKEY new_object(struct handle_table *lpTable, size_t cbSize, DWORD dwType, DESTRUCTOR destructor,
351                         OBJECTHDR **ppObject)
352 {
353     OBJECTHDR *pObject;
354     HCRYPTKEY hObject;
355
356     if (ppObject)
357         *ppObject = NULL;
358
359     pObject = HeapAlloc(GetProcessHeap(), 0, cbSize);
360     if (!pObject)
361         return (HCRYPTKEY)INVALID_HANDLE_VALUE;
362
363     pObject->dwType = dwType;
364     pObject->refcount = 0;
365     pObject->destructor = destructor;
366
367     if (!alloc_handle(lpTable, pObject, &hObject))
368         HeapFree(GetProcessHeap(), 0, pObject);
369     else
370         if (ppObject)
371             *ppObject = pObject;
372
373     return hObject;
374 }