Documentation corrections/standardizations.
[wine] / scheduler / handle.c
1 /*
2  * Win32 process handles
3  *
4  * Copyright 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <stdio.h>
9 #include "debug.h"
10 #include "winbase.h"
11 #include "winerror.h"
12 #include "heap.h"
13 #include "process.h"
14 #include "server.h"
15 #include "thread.h"
16
17 #define HTABLE_SIZE  0x30  /* Handle table initial size */
18 #define HTABLE_INC   0x10  /* Handle table increment */
19
20 /* Reserved access rights */
21 #define RESERVED_ALL           (0x0007 << RESERVED_SHIFT)
22 #define RESERVED_SHIFT         25
23 #define RESERVED_INHERIT       (HANDLE_FLAG_INHERIT<<RESERVED_SHIFT)
24 #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE<<RESERVED_SHIFT)
25
26
27 /***********************************************************************
28  *           HANDLE_GrowTable
29  */
30 static BOOL32 HANDLE_GrowTable( PDB32 *process, INT32 incr )
31 {
32     HANDLE_TABLE *table;
33
34     SYSTEM_LOCK();
35     table = process->handle_table;
36     table = HeapReAlloc( process->system_heap,
37                          HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, table,
38                          sizeof(HANDLE_TABLE) +
39                          (table->count + incr - 1) * sizeof(HANDLE_ENTRY) );
40     if (table)
41     {
42         table->count += incr;
43         process->handle_table = table;
44     }
45     SYSTEM_UNLOCK();
46     return (table != NULL);
47 }
48
49
50 /***********************************************************************
51  *           HANDLE_CreateTable
52  *
53  * Create a process handle table, optionally inheriting the parent's handles.
54  */
55 BOOL32 HANDLE_CreateTable( PDB32 *pdb, BOOL32 inherit )
56 {
57     DWORD size;
58
59     /* Process must not already have a handle table */
60     assert( !pdb->handle_table );
61
62     /* If this is the first process, simply allocate a table */
63     if (!pdb->parent) inherit = FALSE;
64
65     SYSTEM_LOCK();
66     size = inherit ? pdb->parent->handle_table->count : HTABLE_SIZE;
67     if ((pdb->handle_table = HeapAlloc( pdb->system_heap,
68                                         HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE,
69                                         sizeof(HANDLE_TABLE) +
70                                         (size-1) * sizeof(HANDLE_ENTRY) )))
71     {
72         pdb->handle_table->count = size;
73         if (inherit)
74         {
75             HANDLE_ENTRY *src = pdb->parent->handle_table->entries;
76             HANDLE_ENTRY *dst = pdb->handle_table->entries;
77             HANDLE32 h;
78
79             for (h = 0; h < size; h++, src++, dst++)
80             {
81                 /* Check if handle is valid and inheritable */
82                 if (src->ptr && (src->access & RESERVED_INHERIT))
83                 {
84                     dst->access = src->access;
85                     dst->ptr    = src->ptr;
86                     dst->server = src->server;
87                     K32OBJ_IncCount( dst->ptr );
88                 }
89             }
90         }
91         /* Handle 1 is the process itself (unless the parent decided otherwise) */
92         if (!pdb->handle_table->entries[1].ptr)
93         {
94             pdb->handle_table->entries[1].ptr    = &pdb->header;
95             pdb->handle_table->entries[1].access = PROCESS_ALL_ACCESS;
96             pdb->handle_table->entries[1].server = -1;  /* FIXME */
97             K32OBJ_IncCount( &pdb->header );
98         }
99     }
100     SYSTEM_UNLOCK();
101     return (pdb->handle_table != NULL);
102 }
103
104
105 /***********************************************************************
106  *           HANDLE_Alloc
107  *
108  * Allocate a handle for a kernel object and increment its refcount.
109  */
110 HANDLE32 HANDLE_Alloc( PDB32 *pdb, K32OBJ *ptr, DWORD access,
111                        BOOL32 inherit, int server_handle )
112 {
113     HANDLE32 h;
114     HANDLE_ENTRY *entry;
115
116     assert( ptr );
117
118     /* Set the inherit reserved flag */
119     access &= ~RESERVED_ALL;
120     if (inherit) access |= RESERVED_INHERIT;
121
122     SYSTEM_LOCK();
123     K32OBJ_IncCount( ptr );
124     /* Don't try to allocate handle 0 */
125     entry = pdb->handle_table->entries + 1;
126     for (h = 1; h < pdb->handle_table->count; h++, entry++)
127         if (!entry->ptr) break;
128     if ((h < pdb->handle_table->count) || HANDLE_GrowTable( pdb, HTABLE_INC ))
129     {
130         entry = &pdb->handle_table->entries[h];
131         entry->access = access;
132         entry->ptr    = ptr;
133         entry->server = server_handle;
134         SYSTEM_UNLOCK();
135         return h;
136     }
137     K32OBJ_DecCount( ptr );
138     SYSTEM_UNLOCK();
139     if (server_handle != -1) CLIENT_CloseHandle( server_handle );
140     SetLastError( ERROR_OUTOFMEMORY );
141     return INVALID_HANDLE_VALUE32;
142 }
143
144
145 /***********************************************************************
146  *           HANDLE_GetObjPtr
147  *
148  * Retrieve a pointer to a kernel object and increments its reference count.
149  * The refcount must be decremented when the pointer is no longer used.
150  */
151 K32OBJ *HANDLE_GetObjPtr( PDB32 *pdb, HANDLE32 handle,
152                           K32OBJ_TYPE type, DWORD access,
153                           int *server_handle )
154 {
155     K32OBJ *ptr = NULL;
156
157     SYSTEM_LOCK();
158     if ((handle > 0) && (handle <= pdb->handle_table->count))
159     {
160         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
161         if ((entry->access & access) != access)
162             WARN(win32, "Handle %08x bad access (acc=%08lx req=%08lx)\n",
163                      handle, entry->access, access );
164         ptr = entry->ptr;
165         if (server_handle) *server_handle = entry->server;
166     }
167     else if (handle == CURRENT_THREAD_PSEUDOHANDLE)
168     {
169        ptr = (K32OBJ *)THREAD_Current();
170        if (server_handle) *server_handle = CURRENT_THREAD_PSEUDOHANDLE;
171     }
172     else if (handle == CURRENT_PROCESS_PSEUDOHANDLE)
173     {
174        ptr = (K32OBJ *)PROCESS_Current();
175        if (server_handle) *server_handle = CURRENT_PROCESS_PSEUDOHANDLE;
176     }
177
178     if (ptr && ((type == K32OBJ_UNKNOWN) || (ptr->type == type)))
179         K32OBJ_IncCount( ptr );
180     else
181         ptr = NULL;
182
183     SYSTEM_UNLOCK();
184     if (!ptr) SetLastError( ERROR_INVALID_HANDLE );
185     return ptr;
186 }
187
188
189 /***********************************************************************
190  *           HANDLE_SetObjPtr
191  *
192  * Change the object pointer of a handle, and increment the refcount.
193  * Use with caution!
194  */
195 BOOL32 HANDLE_SetObjPtr( PDB32 *pdb, HANDLE32 handle, K32OBJ *ptr,
196                          DWORD access )
197 {
198     BOOL32 ret = FALSE;
199
200     SYSTEM_LOCK();
201     if ((handle > 0) && (handle <= pdb->handle_table->count))
202     {
203         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
204         K32OBJ *old_ptr = entry->ptr;
205         K32OBJ_IncCount( ptr );
206         entry->access = access;
207         entry->ptr    = ptr;
208         if (old_ptr) K32OBJ_DecCount( old_ptr );
209         ret = TRUE;
210     }
211     SYSTEM_UNLOCK();
212     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
213     return ret;
214 }
215
216
217 /*********************************************************************
218  *           HANDLE_GetAccess
219  */
220 static BOOL32 HANDLE_GetAccess( PDB32 *pdb, HANDLE32 handle, LPDWORD access )
221 {
222     BOOL32 ret = FALSE;
223
224     SYSTEM_LOCK();
225     if ((handle > 0) && (handle <= pdb->handle_table->count))
226     {
227         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
228         if (entry->ptr)
229         {
230             *access = entry->access & ~RESERVED_ALL;
231             ret = TRUE;
232         }
233     }
234     SYSTEM_UNLOCK();
235     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
236     return ret;
237 }
238
239
240 /*********************************************************************
241  *           HANDLE_Close
242  */
243 static BOOL32 HANDLE_Close( PDB32 *pdb, HANDLE32 handle )
244 {
245     BOOL32 ret = FALSE;
246     K32OBJ *ptr;
247
248     SYSTEM_LOCK();
249     if ((handle > 0) && (handle <= pdb->handle_table->count))
250     {
251         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
252         if ((ptr = entry->ptr))
253         {
254             if (!(entry->access & RESERVED_CLOSE_PROTECT))
255             {
256                 entry->access = 0;
257                 entry->ptr    = NULL;
258                 if (entry->server != -1)
259                     CLIENT_CloseHandle( entry->server );
260                 K32OBJ_DecCount( ptr );
261                 ret = TRUE;
262             }
263             /* FIXME: else SetLastError */
264         }
265     }
266     SYSTEM_UNLOCK();
267     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
268     return ret;
269 }
270
271
272 /*********************************************************************
273  *           HANDLE_CloseAll
274  *
275  * Close all handles pointing to a given object (or all handles of the
276  * process if the object is NULL)
277  */
278 void HANDLE_CloseAll( PDB32 *pdb, K32OBJ *obj )
279 {
280     HANDLE_ENTRY *entry;
281     K32OBJ *ptr;
282     HANDLE32 handle;
283
284     SYSTEM_LOCK();
285     entry = pdb->handle_table->entries;
286     for (handle = 0; handle < pdb->handle_table->count; handle++, entry++)
287     {
288         if (!(ptr = entry->ptr)) continue;  /* empty slot */
289         if (obj && (ptr != obj)) continue;  /* not the right object */
290         entry->access = 0;
291         entry->ptr    = NULL;
292         if (entry->server != -1) CLIENT_CloseHandle( entry->server );
293         K32OBJ_DecCount( ptr );
294     }
295     SYSTEM_UNLOCK();
296 }
297
298
299 /*********************************************************************
300  *           CloseHandle   (KERNEL32.23)
301  */
302 BOOL32 WINAPI CloseHandle( HANDLE32 handle )
303 {
304     return HANDLE_Close( PROCESS_Current(), handle );
305 }
306
307
308 /*********************************************************************
309  *           GetHandleInformation   (KERNEL32.336)
310  */
311 BOOL32 WINAPI GetHandleInformation( HANDLE32 handle, LPDWORD flags )
312 {
313     BOOL32 ret = FALSE;
314     PDB32 *pdb = PROCESS_Current();
315
316     SYSTEM_LOCK();
317     if ((handle > 0) && (handle <= pdb->handle_table->count))
318     {
319         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
320         if (entry->ptr)
321         {
322             if (flags)
323                 *flags = (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
324             ret = TRUE;
325         }
326     }
327     SYSTEM_UNLOCK();
328     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
329     return ret;
330 }
331
332
333 /*********************************************************************
334  *           SetHandleInformation   (KERNEL32.653)
335  */
336 BOOL32 WINAPI SetHandleInformation( HANDLE32 handle, DWORD mask, DWORD flags )
337 {
338     BOOL32 ret = FALSE;
339     PDB32 *pdb = PROCESS_Current();
340
341     mask  = (mask << RESERVED_SHIFT) & RESERVED_ALL;
342     flags = (flags << RESERVED_SHIFT) & RESERVED_ALL;
343     SYSTEM_LOCK();
344     if ((handle > 0) && (handle <= pdb->handle_table->count))
345     {
346         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
347         if (entry->ptr)
348         {
349             entry->access = (entry->access & ~mask) | flags;
350             ret = TRUE;
351         }
352     }
353     SYSTEM_UNLOCK();
354     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
355     return ret;
356 }
357
358
359 /*********************************************************************
360  *           DuplicateHandle   (KERNEL32.192)
361  */
362 BOOL32 WINAPI DuplicateHandle( HANDLE32 source_process, HANDLE32 source,
363                                HANDLE32 dest_process, HANDLE32 *dest,
364                                DWORD access, BOOL32 inherit, DWORD options )
365 {
366     PDB32 *src_pdb = NULL, *dst_pdb = NULL;
367     K32OBJ *obj = NULL;
368     BOOL32 ret = FALSE;
369     HANDLE32 handle;
370     int src_process, src_handle, dst_process, dst_handle;
371
372     SYSTEM_LOCK();
373
374     if (!(src_pdb = PROCESS_GetPtr( source_process, PROCESS_DUP_HANDLE, &src_process )))
375         goto done;
376     if (!(obj = HANDLE_GetObjPtr( src_pdb, source, K32OBJ_UNKNOWN, 0, &src_handle )))
377         goto done;
378
379     /* Now that we are sure the source is valid, handle the options */
380
381     if (options & DUPLICATE_SAME_ACCESS)
382         HANDLE_GetAccess( src_pdb, source, &access );
383     if (options & DUPLICATE_CLOSE_SOURCE)
384         HANDLE_Close( src_pdb, source );
385
386     /* And duplicate the handle in the dest process */
387
388     if (!(dst_pdb = PROCESS_GetPtr( dest_process, PROCESS_DUP_HANDLE, &dst_process )))
389         goto done;
390
391     if ((src_process != -1) && (src_handle != -1) && (dst_process != -1))
392         dst_handle = CLIENT_DuplicateHandle( src_process, src_handle, dst_process, -1,
393                                              access, inherit, options );
394     else
395         dst_handle = -1;
396
397     if ((handle = HANDLE_Alloc( dst_pdb, obj, access, inherit,
398                                 dst_handle )) != INVALID_HANDLE_VALUE32)
399     {
400         if (dest) *dest = handle;
401         ret = TRUE;
402     }
403
404 done:
405     if (dst_pdb) K32OBJ_DecCount( &dst_pdb->header );
406     if (obj) K32OBJ_DecCount( obj );
407     if (src_pdb) K32OBJ_DecCount( &src_pdb->header );
408     SYSTEM_UNLOCK();
409     return ret;
410 }