2 * Win32 process handles
4 * Copyright 1998 Alexandre Julliard
17 #define HTABLE_SIZE 0x30 /* Handle table initial size */
18 #define HTABLE_INC 0x10 /* Handle table increment */
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)
27 /***********************************************************************
30 static BOOL32 HANDLE_GrowTable( PDB32 *process, INT32 incr )
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) );
43 process->handle_table = table;
46 return (table != NULL);
50 /***********************************************************************
53 * Create a process handle table, optionally inheriting the parent's handles.
55 BOOL32 HANDLE_CreateTable( PDB32 *pdb, BOOL32 inherit )
59 /* Process must not already have a handle table */
60 assert( !pdb->handle_table );
62 /* If this is the first process, simply allocate a table */
63 if (!pdb->parent) inherit = FALSE;
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) )))
72 pdb->handle_table->count = size;
75 HANDLE_ENTRY *src = pdb->parent->handle_table->entries;
76 HANDLE_ENTRY *dst = pdb->handle_table->entries;
79 for (h = 0; h < size; h++, src++, dst++)
81 /* Check if handle is valid and inheritable */
82 if (src->ptr && (src->access & RESERVED_INHERIT))
84 dst->access = src->access;
86 dst->server = src->server;
87 K32OBJ_IncCount( dst->ptr );
91 /* Handle 1 is the process itself (unless the parent decided otherwise) */
92 if (!pdb->handle_table->entries[1].ptr)
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 );
101 return (pdb->handle_table != NULL);
105 /***********************************************************************
108 * Allocate a handle for a kernel object and increment its refcount.
110 HANDLE32 HANDLE_Alloc( PDB32 *pdb, K32OBJ *ptr, DWORD access,
111 BOOL32 inherit, int server_handle )
118 /* Set the inherit reserved flag */
119 access &= ~RESERVED_ALL;
120 if (inherit) access |= RESERVED_INHERIT;
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 ))
130 entry = &pdb->handle_table->entries[h];
131 entry->access = access;
133 entry->server = server_handle;
137 K32OBJ_DecCount( ptr );
139 if (server_handle != -1) CLIENT_CloseHandle( server_handle );
140 SetLastError( ERROR_OUTOFMEMORY );
141 return INVALID_HANDLE_VALUE32;
145 /***********************************************************************
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.
151 K32OBJ *HANDLE_GetObjPtr( PDB32 *pdb, HANDLE32 handle,
152 K32OBJ_TYPE type, DWORD access,
158 if ((handle > 0) && (handle <= pdb->handle_table->count))
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 );
165 if (server_handle) *server_handle = entry->server;
167 else if (handle == CURRENT_THREAD_PSEUDOHANDLE)
169 ptr = (K32OBJ *)THREAD_Current();
170 if (server_handle) *server_handle = CURRENT_THREAD_PSEUDOHANDLE;
172 else if (handle == CURRENT_PROCESS_PSEUDOHANDLE)
174 ptr = (K32OBJ *)PROCESS_Current();
175 if (server_handle) *server_handle = CURRENT_PROCESS_PSEUDOHANDLE;
178 if (ptr && ((type == K32OBJ_UNKNOWN) || (ptr->type == type)))
179 K32OBJ_IncCount( ptr );
184 if (!ptr) SetLastError( ERROR_INVALID_HANDLE );
189 /***********************************************************************
192 * Change the object pointer of a handle, and increment the refcount.
195 BOOL32 HANDLE_SetObjPtr( PDB32 *pdb, HANDLE32 handle, K32OBJ *ptr,
201 if ((handle > 0) && (handle <= pdb->handle_table->count))
203 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
204 K32OBJ *old_ptr = entry->ptr;
205 K32OBJ_IncCount( ptr );
206 entry->access = access;
208 if (old_ptr) K32OBJ_DecCount( old_ptr );
212 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
217 /*********************************************************************
220 static BOOL32 HANDLE_GetAccess( PDB32 *pdb, HANDLE32 handle, LPDWORD access )
225 if ((handle > 0) && (handle <= pdb->handle_table->count))
227 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
230 *access = entry->access & ~RESERVED_ALL;
235 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
240 /*********************************************************************
243 static BOOL32 HANDLE_Close( PDB32 *pdb, HANDLE32 handle )
249 if ((handle > 0) && (handle <= pdb->handle_table->count))
251 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
252 if ((ptr = entry->ptr))
254 if (!(entry->access & RESERVED_CLOSE_PROTECT))
258 if (entry->server != -1)
259 CLIENT_CloseHandle( entry->server );
260 K32OBJ_DecCount( ptr );
263 /* FIXME: else SetLastError */
267 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
272 /*********************************************************************
275 * Close all handles pointing to a given object (or all handles of the
276 * process if the object is NULL)
278 void HANDLE_CloseAll( PDB32 *pdb, K32OBJ *obj )
285 entry = pdb->handle_table->entries;
286 for (handle = 0; handle < pdb->handle_table->count; handle++, entry++)
288 if (!(ptr = entry->ptr)) continue; /* empty slot */
289 if (obj && (ptr != obj)) continue; /* not the right object */
292 if (entry->server != -1) CLIENT_CloseHandle( entry->server );
293 K32OBJ_DecCount( ptr );
299 /*********************************************************************
300 * CloseHandle (KERNEL32.23)
302 BOOL32 WINAPI CloseHandle( HANDLE32 handle )
304 return HANDLE_Close( PROCESS_Current(), handle );
308 /*********************************************************************
309 * GetHandleInformation (KERNEL32.336)
311 BOOL32 WINAPI GetHandleInformation( HANDLE32 handle, LPDWORD flags )
314 PDB32 *pdb = PROCESS_Current();
317 if ((handle > 0) && (handle <= pdb->handle_table->count))
319 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
323 *flags = (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
328 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
333 /*********************************************************************
334 * SetHandleInformation (KERNEL32.653)
336 BOOL32 WINAPI SetHandleInformation( HANDLE32 handle, DWORD mask, DWORD flags )
339 PDB32 *pdb = PROCESS_Current();
341 mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
342 flags = (flags << RESERVED_SHIFT) & RESERVED_ALL;
344 if ((handle > 0) && (handle <= pdb->handle_table->count))
346 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
349 entry->access = (entry->access & ~mask) | flags;
354 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
359 /*********************************************************************
360 * DuplicateHandle (KERNEL32.192)
362 BOOL32 WINAPI DuplicateHandle( HANDLE32 source_process, HANDLE32 source,
363 HANDLE32 dest_process, HANDLE32 *dest,
364 DWORD access, BOOL32 inherit, DWORD options )
366 PDB32 *src_pdb = NULL, *dst_pdb = NULL;
370 int src_process, src_handle, dst_process, dst_handle;
374 if (!(src_pdb = PROCESS_GetPtr( source_process, PROCESS_DUP_HANDLE, &src_process )))
376 if (!(obj = HANDLE_GetObjPtr( src_pdb, source, K32OBJ_UNKNOWN, 0, &src_handle )))
379 /* Now that we are sure the source is valid, handle the options */
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 );
386 /* And duplicate the handle in the dest process */
388 if (!(dst_pdb = PROCESS_GetPtr( dest_process, PROCESS_DUP_HANDLE, &dst_process )))
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 );
397 if ((handle = HANDLE_Alloc( dst_pdb, obj, access, inherit,
398 dst_handle )) != INVALID_HANDLE_VALUE32)
400 if (dest) *dest = handle;
405 if (dst_pdb) K32OBJ_DecCount( &dst_pdb->header );
406 if (obj) K32OBJ_DecCount( obj );
407 if (src_pdb) K32OBJ_DecCount( &src_pdb->header );