GetBinaryType[AW] moved to loader/module.c, modified to recognize .COM
[wine/wine-kai.git] / scheduler / handle.c
blob032921b0e2a18c2ae2f50ae6085defb5d33ba643
1 /*
2 * Win32 process handles
4 * Copyright 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <stdio.h>
9 #include "winbase.h"
10 #include "winerror.h"
11 #include "heap.h"
12 #include "process.h"
13 #include "server.h"
14 #include "thread.h"
15 #include "debug.h"
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 /***********************************************************************
28 * HANDLE_GrowTable
30 static BOOL HANDLE_GrowTable( PDB *process, INT incr )
32 HANDLE_TABLE *table;
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)
42 table->count += incr;
43 process->handle_table = table;
45 SYSTEM_UNLOCK();
46 return (table != NULL);
50 /***********************************************************************
51 * HANDLE_CreateTable
53 * Create a process handle table, optionally inheriting the parent's handles.
55 BOOL HANDLE_CreateTable( PDB *pdb, BOOL inherit )
57 DWORD size;
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;
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) )))
72 pdb->handle_table->count = size;
73 if (inherit)
75 HANDLE_ENTRY *src = pdb->parent->handle_table->entries;
76 HANDLE_ENTRY *dst = pdb->handle_table->entries;
77 HANDLE h;
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;
85 dst->ptr = src->ptr;
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 );
100 SYSTEM_UNLOCK();
101 return (pdb->handle_table != NULL);
105 /***********************************************************************
106 * HANDLE_Alloc
108 * Allocate a handle for a kernel object and increment its refcount.
110 HANDLE HANDLE_Alloc( PDB *pdb, K32OBJ *ptr, DWORD access,
111 BOOL inherit, int server_handle )
113 HANDLE h;
114 HANDLE_ENTRY *entry;
116 assert( ptr );
118 /* Set the inherit reserved flag */
119 access &= ~RESERVED_ALL;
120 if (inherit) access |= RESERVED_INHERIT;
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 ))
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;
137 K32OBJ_DecCount( ptr );
138 SYSTEM_UNLOCK();
139 if (server_handle != -1) CLIENT_CloseHandle( server_handle );
140 SetLastError( ERROR_OUTOFMEMORY );
141 return INVALID_HANDLE_VALUE;
145 /***********************************************************************
146 * HANDLE_GetObjPtr
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( PDB *pdb, HANDLE handle,
152 K32OBJ_TYPE type, DWORD access,
153 int *server_handle )
155 K32OBJ *ptr = NULL;
157 SYSTEM_LOCK();
158 if (HANDLE_IS_GLOBAL( handle ))
160 handle = HANDLE_GLOBAL_TO_LOCAL( handle );
161 pdb = PROCESS_Initial();
163 if ((handle > 0) && (handle < pdb->handle_table->count))
165 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
166 if ((entry->access & access) != access)
167 WARN(win32, "Handle %08x bad access (acc=%08lx req=%08lx)\n",
168 handle, entry->access, access );
169 ptr = entry->ptr;
170 if (server_handle) *server_handle = entry->server;
172 else if (handle == CURRENT_THREAD_PSEUDOHANDLE)
174 ptr = (K32OBJ *)THREAD_Current();
175 if (server_handle) *server_handle = CURRENT_THREAD_PSEUDOHANDLE;
177 else if (handle == CURRENT_PROCESS_PSEUDOHANDLE)
179 ptr = (K32OBJ *)PROCESS_Current();
180 if (server_handle) *server_handle = CURRENT_PROCESS_PSEUDOHANDLE;
183 if (ptr && ((type == K32OBJ_UNKNOWN) || (ptr->type == type)))
184 K32OBJ_IncCount( ptr );
185 else
186 ptr = NULL;
188 SYSTEM_UNLOCK();
189 if (!ptr) SetLastError( ERROR_INVALID_HANDLE );
190 return ptr;
194 /***********************************************************************
195 * HANDLE_GetServerHandle
197 * Retrieve the server handle associated to an object.
199 int HANDLE_GetServerHandle( PDB *pdb, HANDLE handle,
200 K32OBJ_TYPE type, DWORD access )
202 int server_handle;
203 K32OBJ *obj;
205 SYSTEM_LOCK();
206 if ((obj = HANDLE_GetObjPtr( pdb, handle, type, access, &server_handle )))
207 K32OBJ_DecCount( obj );
208 else
209 server_handle = -1;
210 SYSTEM_UNLOCK();
211 return server_handle;
215 /*********************************************************************
216 * HANDLE_GetAccess
218 static BOOL HANDLE_GetAccess( PDB *pdb, HANDLE handle, LPDWORD access )
220 BOOL ret = FALSE;
222 SYSTEM_LOCK();
223 if ((handle > 0) && (handle < pdb->handle_table->count))
225 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
226 if (entry->ptr)
228 *access = entry->access & ~RESERVED_ALL;
229 ret = TRUE;
232 SYSTEM_UNLOCK();
233 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
234 return ret;
238 /*********************************************************************
239 * HANDLE_Close
241 static BOOL HANDLE_Close( PDB *pdb, HANDLE handle )
243 BOOL ret = FALSE;
244 K32OBJ *ptr;
246 if (HANDLE_IS_GLOBAL( handle ))
248 handle = HANDLE_GLOBAL_TO_LOCAL( handle );
249 pdb = PROCESS_Initial();
251 SYSTEM_LOCK();
252 if ((handle > 0) && (handle < pdb->handle_table->count))
254 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
255 if ((ptr = entry->ptr))
257 if (!(entry->access & RESERVED_CLOSE_PROTECT))
259 entry->access = 0;
260 entry->ptr = NULL;
261 if (entry->server != -1)
262 CLIENT_CloseHandle( entry->server );
263 K32OBJ_DecCount( ptr );
264 ret = TRUE;
266 /* FIXME: else SetLastError */
269 SYSTEM_UNLOCK();
270 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
271 return ret;
275 /*********************************************************************
276 * HANDLE_CloseAll
278 * Close all handles pointing to a given object (or all handles of the
279 * process if the object is NULL)
281 void HANDLE_CloseAll( PDB *pdb, K32OBJ *obj )
283 HANDLE_ENTRY *entry;
284 K32OBJ *ptr;
285 HANDLE handle;
287 SYSTEM_LOCK();
288 entry = pdb->handle_table->entries;
289 for (handle = 0; handle < pdb->handle_table->count; handle++, entry++)
291 if (!(ptr = entry->ptr)) continue; /* empty slot */
292 if (obj && (ptr != obj)) continue; /* not the right object */
293 entry->access = 0;
294 entry->ptr = NULL;
295 if (entry->server != -1) CLIENT_CloseHandle( entry->server );
296 K32OBJ_DecCount( ptr );
298 SYSTEM_UNLOCK();
302 /*********************************************************************
303 * CloseHandle (KERNEL32.23)
305 BOOL WINAPI CloseHandle( HANDLE handle )
307 return HANDLE_Close( PROCESS_Current(), handle );
311 /*********************************************************************
312 * GetHandleInformation (KERNEL32.336)
314 BOOL WINAPI GetHandleInformation( HANDLE handle, LPDWORD flags )
316 BOOL ret = FALSE;
317 PDB *pdb = PROCESS_Current();
319 SYSTEM_LOCK();
320 if ((handle > 0) && (handle < pdb->handle_table->count))
322 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
323 if (entry->ptr)
325 if (flags)
326 *flags = (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
327 ret = TRUE;
330 SYSTEM_UNLOCK();
331 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
332 return ret;
336 /*********************************************************************
337 * SetHandleInformation (KERNEL32.653)
339 BOOL WINAPI SetHandleInformation( HANDLE handle, DWORD mask, DWORD flags )
341 BOOL ret = FALSE;
342 PDB *pdb = PROCESS_Current();
344 mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
345 flags = (flags << RESERVED_SHIFT) & RESERVED_ALL;
346 SYSTEM_LOCK();
347 if ((handle > 0) && (handle < pdb->handle_table->count))
349 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
350 if (entry->ptr)
352 entry->access = (entry->access & ~mask) | flags;
353 ret = TRUE;
356 SYSTEM_UNLOCK();
357 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
358 return ret;
362 /*********************************************************************
363 * DuplicateHandle (KERNEL32.192)
365 BOOL WINAPI DuplicateHandle( HANDLE source_process, HANDLE source,
366 HANDLE dest_process, HANDLE *dest,
367 DWORD access, BOOL inherit, DWORD options )
369 PDB *src_pdb = NULL, *dst_pdb = NULL;
370 K32OBJ *obj = NULL;
371 BOOL ret = FALSE;
372 HANDLE handle;
373 int src_process, src_handle, dst_process, dst_handle;
375 SYSTEM_LOCK();
377 if (!(src_pdb = (PDB *)HANDLE_GetObjPtr( PROCESS_Current(), source_process,
378 K32OBJ_PROCESS, PROCESS_DUP_HANDLE, &src_process )))
379 goto done;
380 if (!(obj = HANDLE_GetObjPtr( src_pdb, source, K32OBJ_UNKNOWN, 0, &src_handle )))
381 goto done;
383 /* Now that we are sure the source is valid, handle the options */
385 if (options & DUPLICATE_SAME_ACCESS)
386 HANDLE_GetAccess( src_pdb, source, &access );
387 if (options & DUPLICATE_CLOSE_SOURCE)
388 HANDLE_Close( src_pdb, source );
390 /* And duplicate the handle in the dest process */
392 if (!(dst_pdb = (PDB *)HANDLE_GetObjPtr( PROCESS_Current(), dest_process,
393 K32OBJ_PROCESS, PROCESS_DUP_HANDLE, &dst_process )))
394 goto done;
396 if ((src_process != -1) && (src_handle != -1) && (dst_process != -1))
397 dst_handle = CLIENT_DuplicateHandle( src_process, src_handle, dst_process, -1,
398 access, inherit, options );
399 else
400 dst_handle = -1;
402 if ((handle = HANDLE_Alloc( dst_pdb, obj, access, inherit,
403 dst_handle )) != INVALID_HANDLE_VALUE)
405 if (dest) *dest = handle;
406 ret = TRUE;
409 done:
410 if (dst_pdb) K32OBJ_DecCount( &dst_pdb->header );
411 if (obj) K32OBJ_DecCount( obj );
412 if (src_pdb) K32OBJ_DecCount( &src_pdb->header );
413 SYSTEM_UNLOCK();
414 return ret;
418 /***********************************************************************
419 * ConvertToGlobalHandle (KERNEL32)
421 HANDLE WINAPI ConvertToGlobalHandle(HANDLE hSrc)
423 int src_handle, dst_handle;
424 HANDLE handle;
425 K32OBJ *obj = NULL;
426 DWORD access;
428 if (HANDLE_IS_GLOBAL(hSrc))
429 return hSrc;
431 if (!(obj = HANDLE_GetObjPtr( PROCESS_Current(), hSrc, K32OBJ_UNKNOWN, 0, &src_handle )))
432 return 0;
434 HANDLE_GetAccess( PROCESS_Current(), hSrc, &access );
436 if (src_handle != -1)
437 dst_handle = CLIENT_DuplicateHandle( GetCurrentProcess(), src_handle, -1, -1, 0, FALSE,
438 DUP_HANDLE_MAKE_GLOBAL | DUP_HANDLE_SAME_ACCESS );
439 else
440 dst_handle = -1;
442 if ((handle = HANDLE_Alloc( PROCESS_Initial(), obj, access, FALSE,
443 dst_handle )) != INVALID_HANDLE_VALUE)
444 handle = HANDLE_LOCAL_TO_GLOBAL(handle);
445 else
446 handle = 0;
448 CloseHandle( hSrc );
449 return handle;