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