
Added user APCs support. Many changes to the xterm console to make use of the server (not finished yet). Moved some other small stuff to the server.
449 lines
13 KiB
C
449 lines
13 KiB
C
/*
|
|
* Win32 process handles
|
|
*
|
|
* Copyright 1998 Alexandre Julliard
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include "winbase.h"
|
|
#include "winerror.h"
|
|
#include "heap.h"
|
|
#include "process.h"
|
|
#include "server.h"
|
|
#include "thread.h"
|
|
#include "debug.h"
|
|
|
|
#define HTABLE_SIZE 0x30 /* Handle table initial size */
|
|
#define HTABLE_INC 0x10 /* Handle table increment */
|
|
|
|
/* Reserved access rights */
|
|
#define RESERVED_ALL (0x0007 << RESERVED_SHIFT)
|
|
#define RESERVED_SHIFT 25
|
|
#define RESERVED_INHERIT (HANDLE_FLAG_INHERIT<<RESERVED_SHIFT)
|
|
#define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE<<RESERVED_SHIFT)
|
|
|
|
|
|
/***********************************************************************
|
|
* HANDLE_GrowTable
|
|
*/
|
|
static BOOL32 HANDLE_GrowTable( PDB32 *process, INT32 incr )
|
|
{
|
|
HANDLE_TABLE *table;
|
|
|
|
SYSTEM_LOCK();
|
|
table = process->handle_table;
|
|
table = HeapReAlloc( process->system_heap,
|
|
HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, table,
|
|
sizeof(HANDLE_TABLE) +
|
|
(table->count + incr - 1) * sizeof(HANDLE_ENTRY) );
|
|
if (table)
|
|
{
|
|
table->count += incr;
|
|
process->handle_table = table;
|
|
}
|
|
SYSTEM_UNLOCK();
|
|
return (table != NULL);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* HANDLE_CreateTable
|
|
*
|
|
* Create a process handle table, optionally inheriting the parent's handles.
|
|
*/
|
|
BOOL32 HANDLE_CreateTable( PDB32 *pdb, BOOL32 inherit )
|
|
{
|
|
DWORD size;
|
|
|
|
/* Process must not already have a handle table */
|
|
assert( !pdb->handle_table );
|
|
|
|
/* If this is the first process, simply allocate a table */
|
|
if (!pdb->parent) inherit = FALSE;
|
|
|
|
SYSTEM_LOCK();
|
|
size = inherit ? pdb->parent->handle_table->count : HTABLE_SIZE;
|
|
if ((pdb->handle_table = HeapAlloc( pdb->system_heap,
|
|
HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE,
|
|
sizeof(HANDLE_TABLE) +
|
|
(size-1) * sizeof(HANDLE_ENTRY) )))
|
|
{
|
|
pdb->handle_table->count = size;
|
|
if (inherit)
|
|
{
|
|
HANDLE_ENTRY *src = pdb->parent->handle_table->entries;
|
|
HANDLE_ENTRY *dst = pdb->handle_table->entries;
|
|
HANDLE32 h;
|
|
|
|
for (h = 0; h < size; h++, src++, dst++)
|
|
{
|
|
/* Check if handle is valid and inheritable */
|
|
if (src->ptr && (src->access & RESERVED_INHERIT))
|
|
{
|
|
dst->access = src->access;
|
|
dst->ptr = src->ptr;
|
|
dst->server = src->server;
|
|
K32OBJ_IncCount( dst->ptr );
|
|
}
|
|
}
|
|
}
|
|
/* Handle 1 is the process itself (unless the parent decided otherwise) */
|
|
if (!pdb->handle_table->entries[1].ptr)
|
|
{
|
|
pdb->handle_table->entries[1].ptr = &pdb->header;
|
|
pdb->handle_table->entries[1].access = PROCESS_ALL_ACCESS;
|
|
pdb->handle_table->entries[1].server = -1; /* FIXME */
|
|
K32OBJ_IncCount( &pdb->header );
|
|
}
|
|
}
|
|
SYSTEM_UNLOCK();
|
|
return (pdb->handle_table != NULL);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* HANDLE_Alloc
|
|
*
|
|
* Allocate a handle for a kernel object and increment its refcount.
|
|
*/
|
|
HANDLE32 HANDLE_Alloc( PDB32 *pdb, K32OBJ *ptr, DWORD access,
|
|
BOOL32 inherit, int server_handle )
|
|
{
|
|
HANDLE32 h;
|
|
HANDLE_ENTRY *entry;
|
|
|
|
assert( ptr );
|
|
|
|
/* Set the inherit reserved flag */
|
|
access &= ~RESERVED_ALL;
|
|
if (inherit) access |= RESERVED_INHERIT;
|
|
|
|
SYSTEM_LOCK();
|
|
K32OBJ_IncCount( ptr );
|
|
/* Don't try to allocate handle 0 */
|
|
entry = pdb->handle_table->entries + 1;
|
|
for (h = 1; h < pdb->handle_table->count; h++, entry++)
|
|
if (!entry->ptr) break;
|
|
if ((h < pdb->handle_table->count) || HANDLE_GrowTable( pdb, HTABLE_INC ))
|
|
{
|
|
entry = &pdb->handle_table->entries[h];
|
|
entry->access = access;
|
|
entry->ptr = ptr;
|
|
entry->server = server_handle;
|
|
SYSTEM_UNLOCK();
|
|
return h;
|
|
}
|
|
K32OBJ_DecCount( ptr );
|
|
SYSTEM_UNLOCK();
|
|
if (server_handle != -1) CLIENT_CloseHandle( server_handle );
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return INVALID_HANDLE_VALUE32;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* HANDLE_GetObjPtr
|
|
*
|
|
* Retrieve a pointer to a kernel object and increments its reference count.
|
|
* The refcount must be decremented when the pointer is no longer used.
|
|
*/
|
|
K32OBJ *HANDLE_GetObjPtr( PDB32 *pdb, HANDLE32 handle,
|
|
K32OBJ_TYPE type, DWORD access,
|
|
int *server_handle )
|
|
{
|
|
K32OBJ *ptr = NULL;
|
|
|
|
SYSTEM_LOCK();
|
|
if (HANDLE_IS_GLOBAL( handle ))
|
|
{
|
|
handle = HANDLE_GLOBAL_TO_LOCAL( handle );
|
|
pdb = PROCESS_Initial();
|
|
}
|
|
if ((handle > 0) && (handle < pdb->handle_table->count))
|
|
{
|
|
HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
|
|
if ((entry->access & access) != access)
|
|
WARN(win32, "Handle %08x bad access (acc=%08lx req=%08lx)\n",
|
|
handle, entry->access, access );
|
|
ptr = entry->ptr;
|
|
if (server_handle) *server_handle = entry->server;
|
|
}
|
|
else if (handle == CURRENT_THREAD_PSEUDOHANDLE)
|
|
{
|
|
ptr = (K32OBJ *)THREAD_Current();
|
|
if (server_handle) *server_handle = CURRENT_THREAD_PSEUDOHANDLE;
|
|
}
|
|
else if (handle == CURRENT_PROCESS_PSEUDOHANDLE)
|
|
{
|
|
ptr = (K32OBJ *)PROCESS_Current();
|
|
if (server_handle) *server_handle = CURRENT_PROCESS_PSEUDOHANDLE;
|
|
}
|
|
|
|
if (ptr && ((type == K32OBJ_UNKNOWN) || (ptr->type == type)))
|
|
K32OBJ_IncCount( ptr );
|
|
else
|
|
ptr = NULL;
|
|
|
|
SYSTEM_UNLOCK();
|
|
if (!ptr) SetLastError( ERROR_INVALID_HANDLE );
|
|
return ptr;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* HANDLE_GetServerHandle
|
|
*
|
|
* Retrieve the server handle associated to an object.
|
|
*/
|
|
int HANDLE_GetServerHandle( PDB32 *pdb, HANDLE32 handle,
|
|
K32OBJ_TYPE type, DWORD access )
|
|
{
|
|
int server_handle;
|
|
K32OBJ *obj;
|
|
|
|
SYSTEM_LOCK();
|
|
if ((obj = HANDLE_GetObjPtr( pdb, handle, type, access, &server_handle )))
|
|
K32OBJ_DecCount( obj );
|
|
else
|
|
server_handle = -1;
|
|
SYSTEM_UNLOCK();
|
|
return server_handle;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* HANDLE_GetAccess
|
|
*/
|
|
static BOOL32 HANDLE_GetAccess( PDB32 *pdb, HANDLE32 handle, LPDWORD access )
|
|
{
|
|
BOOL32 ret = FALSE;
|
|
|
|
SYSTEM_LOCK();
|
|
if ((handle > 0) && (handle < pdb->handle_table->count))
|
|
{
|
|
HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
|
|
if (entry->ptr)
|
|
{
|
|
*access = entry->access & ~RESERVED_ALL;
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
SYSTEM_UNLOCK();
|
|
if (!ret) SetLastError( ERROR_INVALID_HANDLE );
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* HANDLE_Close
|
|
*/
|
|
static BOOL32 HANDLE_Close( PDB32 *pdb, HANDLE32 handle )
|
|
{
|
|
BOOL32 ret = FALSE;
|
|
K32OBJ *ptr;
|
|
|
|
if (HANDLE_IS_GLOBAL( handle ))
|
|
{
|
|
handle = HANDLE_GLOBAL_TO_LOCAL( handle );
|
|
pdb = PROCESS_Initial();
|
|
}
|
|
SYSTEM_LOCK();
|
|
if ((handle > 0) && (handle < pdb->handle_table->count))
|
|
{
|
|
HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
|
|
if ((ptr = entry->ptr))
|
|
{
|
|
if (!(entry->access & RESERVED_CLOSE_PROTECT))
|
|
{
|
|
entry->access = 0;
|
|
entry->ptr = NULL;
|
|
if (entry->server != -1)
|
|
CLIENT_CloseHandle( entry->server );
|
|
K32OBJ_DecCount( ptr );
|
|
ret = TRUE;
|
|
}
|
|
/* FIXME: else SetLastError */
|
|
}
|
|
}
|
|
SYSTEM_UNLOCK();
|
|
if (!ret) SetLastError( ERROR_INVALID_HANDLE );
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* HANDLE_CloseAll
|
|
*
|
|
* Close all handles pointing to a given object (or all handles of the
|
|
* process if the object is NULL)
|
|
*/
|
|
void HANDLE_CloseAll( PDB32 *pdb, K32OBJ *obj )
|
|
{
|
|
HANDLE_ENTRY *entry;
|
|
K32OBJ *ptr;
|
|
HANDLE32 handle;
|
|
|
|
SYSTEM_LOCK();
|
|
entry = pdb->handle_table->entries;
|
|
for (handle = 0; handle < pdb->handle_table->count; handle++, entry++)
|
|
{
|
|
if (!(ptr = entry->ptr)) continue; /* empty slot */
|
|
if (obj && (ptr != obj)) continue; /* not the right object */
|
|
entry->access = 0;
|
|
entry->ptr = NULL;
|
|
if (entry->server != -1) CLIENT_CloseHandle( entry->server );
|
|
K32OBJ_DecCount( ptr );
|
|
}
|
|
SYSTEM_UNLOCK();
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* CloseHandle (KERNEL32.23)
|
|
*/
|
|
BOOL32 WINAPI CloseHandle( HANDLE32 handle )
|
|
{
|
|
return HANDLE_Close( PROCESS_Current(), handle );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* GetHandleInformation (KERNEL32.336)
|
|
*/
|
|
BOOL32 WINAPI GetHandleInformation( HANDLE32 handle, LPDWORD flags )
|
|
{
|
|
BOOL32 ret = FALSE;
|
|
PDB32 *pdb = PROCESS_Current();
|
|
|
|
SYSTEM_LOCK();
|
|
if ((handle > 0) && (handle < pdb->handle_table->count))
|
|
{
|
|
HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
|
|
if (entry->ptr)
|
|
{
|
|
if (flags)
|
|
*flags = (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
SYSTEM_UNLOCK();
|
|
if (!ret) SetLastError( ERROR_INVALID_HANDLE );
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* SetHandleInformation (KERNEL32.653)
|
|
*/
|
|
BOOL32 WINAPI SetHandleInformation( HANDLE32 handle, DWORD mask, DWORD flags )
|
|
{
|
|
BOOL32 ret = FALSE;
|
|
PDB32 *pdb = PROCESS_Current();
|
|
|
|
mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
|
|
flags = (flags << RESERVED_SHIFT) & RESERVED_ALL;
|
|
SYSTEM_LOCK();
|
|
if ((handle > 0) && (handle < pdb->handle_table->count))
|
|
{
|
|
HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
|
|
if (entry->ptr)
|
|
{
|
|
entry->access = (entry->access & ~mask) | flags;
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
SYSTEM_UNLOCK();
|
|
if (!ret) SetLastError( ERROR_INVALID_HANDLE );
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* DuplicateHandle (KERNEL32.192)
|
|
*/
|
|
BOOL32 WINAPI DuplicateHandle( HANDLE32 source_process, HANDLE32 source,
|
|
HANDLE32 dest_process, HANDLE32 *dest,
|
|
DWORD access, BOOL32 inherit, DWORD options )
|
|
{
|
|
PDB32 *src_pdb = NULL, *dst_pdb = NULL;
|
|
K32OBJ *obj = NULL;
|
|
BOOL32 ret = FALSE;
|
|
HANDLE32 handle;
|
|
int src_process, src_handle, dst_process, dst_handle;
|
|
|
|
SYSTEM_LOCK();
|
|
|
|
if (!(src_pdb = PROCESS_GetPtr( source_process, PROCESS_DUP_HANDLE, &src_process )))
|
|
goto done;
|
|
if (!(obj = HANDLE_GetObjPtr( src_pdb, source, K32OBJ_UNKNOWN, 0, &src_handle )))
|
|
goto done;
|
|
|
|
/* Now that we are sure the source is valid, handle the options */
|
|
|
|
if (options & DUPLICATE_SAME_ACCESS)
|
|
HANDLE_GetAccess( src_pdb, source, &access );
|
|
if (options & DUPLICATE_CLOSE_SOURCE)
|
|
HANDLE_Close( src_pdb, source );
|
|
|
|
/* And duplicate the handle in the dest process */
|
|
|
|
if (!(dst_pdb = PROCESS_GetPtr( dest_process, PROCESS_DUP_HANDLE, &dst_process )))
|
|
goto done;
|
|
|
|
if ((src_process != -1) && (src_handle != -1) && (dst_process != -1))
|
|
dst_handle = CLIENT_DuplicateHandle( src_process, src_handle, dst_process, -1,
|
|
access, inherit, options );
|
|
else
|
|
dst_handle = -1;
|
|
|
|
if ((handle = HANDLE_Alloc( dst_pdb, obj, access, inherit,
|
|
dst_handle )) != INVALID_HANDLE_VALUE32)
|
|
{
|
|
if (dest) *dest = handle;
|
|
ret = TRUE;
|
|
}
|
|
|
|
done:
|
|
if (dst_pdb) K32OBJ_DecCount( &dst_pdb->header );
|
|
if (obj) K32OBJ_DecCount( obj );
|
|
if (src_pdb) K32OBJ_DecCount( &src_pdb->header );
|
|
SYSTEM_UNLOCK();
|
|
return ret;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ConvertToGlobalHandle (KERNEL32)
|
|
*/
|
|
HANDLE32 WINAPI ConvertToGlobalHandle(HANDLE32 hSrc)
|
|
{
|
|
int src_handle, dst_handle;
|
|
HANDLE32 handle;
|
|
K32OBJ *obj = NULL;
|
|
DWORD access;
|
|
|
|
if (HANDLE_IS_GLOBAL(hSrc))
|
|
return hSrc;
|
|
|
|
if (!(obj = HANDLE_GetObjPtr( PROCESS_Current(), hSrc, K32OBJ_UNKNOWN, 0, &src_handle )))
|
|
return 0;
|
|
|
|
HANDLE_GetAccess( PROCESS_Current(), hSrc, &access );
|
|
|
|
if (src_handle != -1)
|
|
dst_handle = CLIENT_DuplicateHandle( GetCurrentProcess(), src_handle, -1, -1, 0, FALSE,
|
|
DUP_HANDLE_MAKE_GLOBAL | DUP_HANDLE_SAME_ACCESS );
|
|
else
|
|
dst_handle = -1;
|
|
|
|
if ((handle = HANDLE_Alloc( PROCESS_Initial(), obj, access, FALSE,
|
|
dst_handle )) != INVALID_HANDLE_VALUE32)
|
|
handle = HANDLE_LOCAL_TO_GLOBAL(handle);
|
|
else
|
|
handle = 0;
|
|
|
|
CloseHandle( hSrc );
|
|
return handle;
|
|
}
|