blob: 887fbca920005fc6216f7d15ef27af4c3c973fcf [file] [log] [blame]
Alexandre Julliard43c190e1999-05-15 10:48:19 +00001/*
2 * Server-side handle management
3 *
4 * Copyright (C) 1998 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard43c190e1999-05-15 10:48:19 +000019 */
20
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000021#include "config.h"
22#include "wine/port.h"
23
Alexandre Julliard43c190e1999-05-15 10:48:19 +000024#include <assert.h>
25#include <limits.h>
26#include <string.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000027#include <stdarg.h>
Alexandre Julliard43c190e1999-05-15 10:48:19 +000028#include <stdio.h>
29#include <stdlib.h>
30
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010031#include "ntstatus.h"
32#define WIN32_NO_STATUS
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000033#include "windef.h"
Vitaliy Margolena9960002005-10-27 18:30:37 +000034#include "winternl.h"
Alexandre Julliard43c190e1999-05-15 10:48:19 +000035
36#include "handle.h"
37#include "process.h"
38#include "thread.h"
Alexandre Julliard5bc78081999-06-22 17:26:53 +000039#include "request.h"
Alexandre Julliard43c190e1999-05-15 10:48:19 +000040
41struct handle_entry
42{
Alexandre Julliardd549f692000-12-22 02:04:15 +000043 struct object *ptr; /* object */
44 unsigned int access; /* access rights */
Alexandre Julliard43c190e1999-05-15 10:48:19 +000045};
46
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +000047struct handle_table
48{
49 struct object obj; /* object header */
50 struct process *process; /* process owning this table */
51 int count; /* number of allocated entries */
52 int last; /* last used entry */
53 int free; /* first entry that may be free */
54 struct handle_entry *entries; /* handle entries */
55};
56
57static struct handle_table *global_table;
Alexandre Julliard43c190e1999-05-15 10:48:19 +000058
59/* reserved handle access rights */
Alexandre Julliard78a3e632005-06-09 12:07:12 +000060#define RESERVED_SHIFT 26
Alexandre Julliard43c190e1999-05-15 10:48:19 +000061#define RESERVED_INHERIT (HANDLE_FLAG_INHERIT << RESERVED_SHIFT)
62#define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT)
63#define RESERVED_ALL (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
64
Alexandre Julliard43c190e1999-05-15 10:48:19 +000065#define MIN_HANDLE_ENTRIES 32
66
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +000067
Alexandre Julliardceeb6931999-11-04 02:33:45 +000068/* handle to table index conversion */
69
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000070/* handles are a multiple of 4 under NT; handle 0 is not used */
Alexandre Julliard51885742002-05-30 20:12:58 +000071inline static obj_handle_t index_to_handle( int index )
Alexandre Julliardceeb6931999-11-04 02:33:45 +000072{
Mike McCormacke1c16ff2006-06-15 17:10:07 +090073 return (obj_handle_t)((unsigned long)(index + 1) << 2);
Alexandre Julliardceeb6931999-11-04 02:33:45 +000074}
Alexandre Julliard51885742002-05-30 20:12:58 +000075inline static int handle_to_index( obj_handle_t handle )
Alexandre Julliardceeb6931999-11-04 02:33:45 +000076{
Mike McCormacke1c16ff2006-06-15 17:10:07 +090077 return ((unsigned long)handle >> 2) - 1;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000078}
79
80/* global handle conversion */
81
82#define HANDLE_OBFUSCATOR 0x544a4def
83
Alexandre Julliard51885742002-05-30 20:12:58 +000084inline static int handle_is_global( obj_handle_t handle)
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000085{
86 return ((unsigned long)handle ^ HANDLE_OBFUSCATOR) < 0x10000;
87}
Alexandre Julliard51885742002-05-30 20:12:58 +000088inline static obj_handle_t handle_local_to_global( obj_handle_t handle )
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000089{
90 if (!handle) return 0;
Alexandre Julliard51885742002-05-30 20:12:58 +000091 return (obj_handle_t)((unsigned long)handle ^ HANDLE_OBFUSCATOR);
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000092}
Alexandre Julliard51885742002-05-30 20:12:58 +000093inline static obj_handle_t handle_global_to_local( obj_handle_t handle )
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000094{
Alexandre Julliard51885742002-05-30 20:12:58 +000095 return (obj_handle_t)((unsigned long)handle ^ HANDLE_OBFUSCATOR);
Alexandre Julliardceeb6931999-11-04 02:33:45 +000096}
97
98
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +000099static void handle_table_dump( struct object *obj, int verbose );
100static void handle_table_destroy( struct object *obj );
101
102static const struct object_ops handle_table_ops =
103{
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000104 sizeof(struct handle_table), /* size */
105 handle_table_dump, /* dump */
106 no_add_queue, /* add_queue */
107 NULL, /* remove_queue */
108 NULL, /* signaled */
109 NULL, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +0000110 no_signal, /* signal */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +0000111 no_get_fd, /* get_fd */
Alexandre Julliard28beba32005-12-12 14:57:40 +0100112 no_map_access, /* map_access */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000113 no_lookup_name, /* lookup_name */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000114 no_close_handle, /* close_handle */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000115 handle_table_destroy /* destroy */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000116};
117
118/* dump a handle table */
119static void handle_table_dump( struct object *obj, int verbose )
120{
121 int i;
122 struct handle_table *table = (struct handle_table *)obj;
123 struct handle_entry *entry = table->entries;
124
125 assert( obj->ops == &handle_table_ops );
126
127 fprintf( stderr, "Handle table last=%d count=%d process=%p\n",
128 table->last, table->count, table->process );
129 if (!verbose) return;
130 entry = table->entries;
131 for (i = 0; i <= table->last; i++, entry++)
132 {
133 if (!entry->ptr) continue;
Alexandre Julliard0ec183c2005-09-27 09:36:54 +0000134 fprintf( stderr, " %p: %p %08x ",
135 index_to_handle(i), entry->ptr, entry->access );
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000136 entry->ptr->ops->dump( entry->ptr, 0 );
137 }
138}
139
140/* destroy a handle table */
141static void handle_table_destroy( struct object *obj )
142{
143 int i;
144 struct handle_table *table = (struct handle_table *)obj;
Alexandre Julliard0901b232005-06-14 19:16:56 +0000145 struct handle_entry *entry;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000146
147 assert( obj->ops == &handle_table_ops );
148
Alexandre Julliard0901b232005-06-14 19:16:56 +0000149 /* first notify all objects that handles are being closed */
150 if (table->process)
151 {
152 for (i = 0, entry = table->entries; i <= table->last; i++, entry++)
153 {
154 struct object *obj = entry->ptr;
155 if (obj) obj->ops->close_handle( obj, table->process, index_to_handle(i) );
156 }
157 }
158
159 for (i = 0, entry = table->entries; i <= table->last; i++, entry++)
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000160 {
161 struct object *obj = entry->ptr;
162 entry->ptr = NULL;
163 if (obj) release_object( obj );
164 }
165 free( table->entries );
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000166}
167
168/* allocate a new handle table */
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000169struct handle_table *alloc_handle_table( struct process *process, int count )
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000170{
171 struct handle_table *table;
172
173 if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000174 if (!(table = alloc_object( &handle_table_ops )))
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000175 return NULL;
176 table->process = process;
177 table->count = count;
178 table->last = -1;
179 table->free = 0;
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000180 if ((table->entries = mem_alloc( count * sizeof(*table->entries) ))) return table;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000181 release_object( table );
182 return NULL;
183}
184
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000185/* grow a handle table */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000186static int grow_handle_table( struct handle_table *table )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000187{
188 struct handle_entry *new_entries;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000189 int count = table->count;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000190
191 if (count >= INT_MAX / 2) return 0;
192 count *= 2;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000193 if (!(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000194 {
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000195 set_error( STATUS_NO_MEMORY );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000196 return 0;
197 }
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000198 table->entries = new_entries;
199 table->count = count;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000200 return 1;
201}
202
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000203/* allocate the first free entry in the handle table */
Alexandre Julliard51885742002-05-30 20:12:58 +0000204static obj_handle_t alloc_entry( struct handle_table *table, void *obj, unsigned int access )
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000205{
206 struct handle_entry *entry = table->entries + table->free;
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000207 int i;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000208
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000209 for (i = table->free; i <= table->last; i++, entry++) if (!entry->ptr) goto found;
210 if (i >= table->count)
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000211 {
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000212 if (!grow_handle_table( table )) return 0;
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000213 entry = table->entries + i; /* the entries may have moved */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000214 }
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000215 table->last = i;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000216 found:
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000217 table->free = i + 1;
218 entry->ptr = grab_object( obj );
219 entry->access = access;
220 return index_to_handle(i);
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000221}
222
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000223/* allocate a handle for an object, incrementing its refcount */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000224/* return the handle, or 0 on error */
Alexandre Julliard28beba32005-12-12 14:57:40 +0100225obj_handle_t alloc_handle( struct process *process, void *ptr, unsigned int access, unsigned int attr )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000226{
Alexandre Julliard28beba32005-12-12 14:57:40 +0100227 struct object *obj = ptr;
228
229 access = obj->ops->map_access( obj, access );
Alexandre Julliardc976db12005-07-13 12:09:49 +0000230 access &= ~RESERVED_ALL;
Alexandre Julliard24560e72005-12-09 13:58:25 +0100231 if (attr & OBJ_INHERIT) access |= RESERVED_INHERIT;
Alexandre Julliardc976db12005-07-13 12:09:49 +0000232 if (!process->handles)
233 {
234 set_error( STATUS_NO_MEMORY );
235 return 0;
236 }
237 return alloc_entry( process->handles, obj, access );
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000238}
239
240/* allocate a global handle for an object, incrementing its refcount */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000241/* return the handle, or 0 on error */
Alexandre Julliard51885742002-05-30 20:12:58 +0000242static obj_handle_t alloc_global_handle( void *obj, unsigned int access )
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000243{
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000244 if (!global_table)
245 {
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000246 if (!(global_table = (struct handle_table *)alloc_handle_table( NULL, 0 )))
247 return 0;
Alexandre Julliardb00fb172006-03-22 20:32:04 +0100248 make_object_static( &global_table->obj );
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000249 }
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000250 return handle_local_to_global( alloc_entry( global_table, obj, access ));
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000251}
252
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000253/* return a handle entry, or NULL if the handle is invalid */
Alexandre Julliard51885742002-05-30 20:12:58 +0000254static struct handle_entry *get_handle( struct process *process, obj_handle_t handle )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000255{
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000256 struct handle_table *table = process->handles;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000257 struct handle_entry *entry;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000258 int index;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000259
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000260 if (handle_is_global(handle))
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000261 {
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000262 handle = handle_global_to_local(handle);
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000263 table = global_table;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000264 }
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000265 if (!table) goto error;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000266 index = handle_to_index( handle );
267 if (index < 0) goto error;
268 if (index > table->last) goto error;
269 entry = table->entries + index;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000270 if (!entry->ptr) goto error;
271 return entry;
272
273 error:
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000274 set_error( STATUS_INVALID_HANDLE );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000275 return NULL;
276}
277
278/* attempt to shrink a table */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000279static void shrink_handle_table( struct handle_table *table )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000280{
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000281 struct handle_entry *entry = table->entries + table->last;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000282 struct handle_entry *new_entries;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000283 int count = table->count;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000284
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000285 while (table->last >= 0)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000286 {
287 if (entry->ptr) break;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000288 table->last--;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000289 entry--;
290 }
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000291 if (table->last >= count / 4) return; /* no need to shrink */
292 if (count < MIN_HANDLE_ENTRIES * 2) return; /* too small to shrink */
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000293 count /= 2;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000294 if (!(new_entries = realloc( table->entries, count * sizeof(*new_entries) ))) return;
295 table->count = count;
296 table->entries = new_entries;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000297}
298
299/* copy the handle table of the parent process */
300/* return 1 if OK, 0 on error */
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000301struct handle_table *copy_handle_table( struct process *process, struct process *parent )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000302{
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000303 struct handle_table *parent_table = parent->handles;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000304 struct handle_table *table;
305 int i;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000306
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000307 assert( parent_table );
308 assert( parent_table->obj.ops == &handle_table_ops );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000309
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000310 if (!(table = (struct handle_table *)alloc_handle_table( process, parent_table->count )))
311 return NULL;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000312
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000313 if ((table->last = parent_table->last) >= 0)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000314 {
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000315 struct handle_entry *ptr = table->entries;
316 memcpy( ptr, parent_table->entries, (table->last + 1) * sizeof(struct handle_entry) );
317 for (i = 0; i <= table->last; i++, ptr++)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000318 {
319 if (!ptr->ptr) continue;
320 if (ptr->access & RESERVED_INHERIT) grab_object( ptr->ptr );
321 else ptr->ptr = NULL; /* don't inherit this entry */
322 }
323 }
324 /* attempt to shrink the table */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000325 shrink_handle_table( table );
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000326 return table;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000327}
328
329/* close a handle and decrement the refcount of the associated object */
330/* return 1 if OK, 0 on error */
Alexandre Julliard8700c432006-11-02 20:52:05 +0100331int close_handle( struct process *process, obj_handle_t handle )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000332{
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000333 struct handle_table *table;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000334 struct handle_entry *entry;
335 struct object *obj;
336
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000337 if (!(entry = get_handle( process, handle ))) return 0;
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000338 if (entry->access & RESERVED_CLOSE_PROTECT)
339 {
Alexandre Julliardf895ad12005-07-29 14:41:14 +0000340 set_error( STATUS_HANDLE_NOT_CLOSABLE );
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000341 return 0;
342 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000343 obj = entry->ptr;
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000344 if (!obj->ops->close_handle( obj, process, handle ))
345 {
Alexandre Julliardf895ad12005-07-29 14:41:14 +0000346 set_error( STATUS_HANDLE_NOT_CLOSABLE );
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000347 return 0;
348 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000349 entry->ptr = NULL;
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000350 table = handle_is_global(handle) ? global_table : process->handles;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000351 if (entry < table->entries + table->free) table->free = entry - table->entries;
352 if (entry == table->entries + table->last) shrink_handle_table( table );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000353 release_object( obj );
354 return 1;
355}
356
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000357/* retrieve the object corresponding to one of the magic pseudo-handles */
Alexandre Julliard51885742002-05-30 20:12:58 +0000358static inline struct object *get_magic_handle( obj_handle_t handle )
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000359{
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000360 switch((unsigned long)handle)
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000361 {
362 case 0xfffffffe: /* current thread pseudo-handle */
363 return &current->obj;
364 case 0x7fffffff: /* current process pseudo-handle */
365 case 0xffffffff: /* current process pseudo-handle */
366 return (struct object *)current->process;
367 default:
368 return NULL;
369 }
370}
371
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000372/* retrieve the object corresponding to a handle, incrementing its refcount */
Alexandre Julliard51885742002-05-30 20:12:58 +0000373struct object *get_handle_obj( struct process *process, obj_handle_t handle,
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000374 unsigned int access, const struct object_ops *ops )
375{
376 struct handle_entry *entry;
377 struct object *obj;
378
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000379 if (!(obj = get_magic_handle( handle )))
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000380 {
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000381 if (!(entry = get_handle( process, handle ))) return NULL;
382 if ((entry->access & access) != access)
383 {
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000384 set_error( STATUS_ACCESS_DENIED );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000385 return NULL;
386 }
387 obj = entry->ptr;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000388 }
389 if (ops && (obj->ops != ops))
390 {
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000391 set_error( STATUS_OBJECT_TYPE_MISMATCH ); /* not the right type */
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000392 return NULL;
393 }
394 return grab_object( obj );
395}
396
Mike McCormackf92fff62005-04-24 17:35:52 +0000397/* retrieve the access rights of a given handle */
398unsigned int get_handle_access( struct process *process, obj_handle_t handle )
399{
400 struct handle_entry *entry;
401
402 if (get_magic_handle( handle )) return ~0U; /* magic handles have all access rights */
403 if (!(entry = get_handle( process, handle ))) return 0;
404 return entry->access;
405}
406
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000407/* find the first inherited handle of the given type */
408/* this is needed for window stations and desktops (don't ask...) */
409obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops )
410{
411 struct handle_table *table = process->handles;
412 struct handle_entry *ptr;
413 int i;
414
415 if (!table) return 0;
416
417 for (i = 0, ptr = table->entries; i <= table->last; i++, ptr++)
418 {
419 if (!ptr->ptr) continue;
420 if (ptr->ptr->ops != ops) continue;
421 if (ptr->access & RESERVED_INHERIT) return index_to_handle(i);
422 }
423 return 0;
424}
425
Alexandre Julliardd549f692000-12-22 02:04:15 +0000426/* get/set the handle reserved flags */
427/* return the old flags (or -1 on error) */
Alexandre Julliard38502f72005-08-23 18:43:50 +0000428static int set_handle_flags( struct process *process, obj_handle_t handle, int mask, int flags )
Alexandre Julliardd549f692000-12-22 02:04:15 +0000429{
430 struct handle_entry *entry;
431 unsigned int old_access;
432
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000433 if (get_magic_handle( handle ))
434 {
435 /* we can retrieve but not set info for magic handles */
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000436 if (mask) set_error( STATUS_ACCESS_DENIED );
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000437 return 0;
438 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000439 if (!(entry = get_handle( process, handle ))) return -1;
Alexandre Julliardd549f692000-12-22 02:04:15 +0000440 old_access = entry->access;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000441 mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
442 flags = (flags << RESERVED_SHIFT) & mask;
443 entry->access = (entry->access & ~mask) | flags;
Alexandre Julliardd549f692000-12-22 02:04:15 +0000444 return (old_access & RESERVED_ALL) >> RESERVED_SHIFT;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000445}
446
447/* duplicate a handle */
Alexandre Julliard51885742002-05-30 20:12:58 +0000448obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, struct process *dst,
Alexandre Julliard24560e72005-12-09 13:58:25 +0100449 unsigned int access, unsigned int attr, unsigned int options )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000450{
Alexandre Julliard51885742002-05-30 20:12:58 +0000451 obj_handle_t res;
Alexandre Julliard0042cb31999-05-29 11:17:25 +0000452 struct object *obj = get_handle_obj( src, src_handle, 0, NULL );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000453
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000454 if (!obj) return 0;
Alexandre Julliard0042cb31999-05-29 11:17:25 +0000455 if (options & DUP_HANDLE_SAME_ACCESS)
456 {
457 struct handle_entry *entry = get_handle( src, src_handle );
458 if (entry)
459 access = entry->access;
460 else /* pseudo-handle, give it full access */
461 {
462 access = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000463 clear_error();
Alexandre Julliard0042cb31999-05-29 11:17:25 +0000464 }
465 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000466 access &= ~RESERVED_ALL;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000467 if (options & DUP_HANDLE_MAKE_GLOBAL)
468 res = alloc_global_handle( obj, access );
469 else
Alexandre Julliard24560e72005-12-09 13:58:25 +0100470 res = alloc_handle( dst, obj, access, attr );
Alexandre Julliard0042cb31999-05-29 11:17:25 +0000471 release_object( obj );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000472 return res;
473}
474
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000475/* open a new handle to an existing object */
Alexandre Julliardead9b062005-11-18 16:31:18 +0000476obj_handle_t open_object( const struct namespace *namespace, const struct unicode_str *name,
Vitaliy Margolena9960002005-10-27 18:30:37 +0000477 const struct object_ops *ops, unsigned int access, unsigned int attr )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000478{
Alexandre Julliard51885742002-05-30 20:12:58 +0000479 obj_handle_t handle = 0;
Alexandre Julliardead9b062005-11-18 16:31:18 +0000480 struct object *obj = find_object( namespace, name, attr );
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000481 if (obj)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000482 {
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000483 if (ops && obj->ops != ops)
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000484 set_error( STATUS_OBJECT_TYPE_MISMATCH );
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000485 else
Alexandre Julliard24560e72005-12-09 13:58:25 +0100486 handle = alloc_handle( current->process, obj, access, attr );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000487 release_object( obj );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000488 }
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000489 else
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000490 set_error( STATUS_OBJECT_NAME_NOT_FOUND );
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000491 return handle;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000492}
493
Eric Pouech9fd54b22003-09-16 01:07:21 +0000494/* return the size of the handle table of a given process */
495unsigned int get_handle_table_count( struct process *process )
496{
Alexandre Julliardc976db12005-07-13 12:09:49 +0000497 if (!process->handles) return 0;
Eric Pouech9fd54b22003-09-16 01:07:21 +0000498 return process->handles->count;
499}
500
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000501/* close a handle */
502DECL_HANDLER(close_handle)
503{
Alexandre Julliard8700c432006-11-02 20:52:05 +0100504 close_handle( current->process, req->handle );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000505}
506
507/* set a handle information */
508DECL_HANDLER(set_handle_info)
509{
Alexandre Julliard38502f72005-08-23 18:43:50 +0000510 reply->old_flags = set_handle_flags( current->process, req->handle, req->mask, req->flags );
511}
512
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000513/* duplicate a handle */
514DECL_HANDLER(dup_handle)
515{
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000516 struct process *src, *dst;
517
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000518 reply->handle = 0;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000519 if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
520 {
521 if (req->options & DUP_HANDLE_MAKE_GLOBAL)
522 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000523 reply->handle = duplicate_handle( src, req->src_handle, NULL,
Alexandre Julliard24560e72005-12-09 13:58:25 +0100524 req->access, req->attributes, req->options );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000525 }
526 else if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
527 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000528 reply->handle = duplicate_handle( src, req->src_handle, dst,
Alexandre Julliard24560e72005-12-09 13:58:25 +0100529 req->access, req->attributes, req->options );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000530 release_object( dst );
531 }
532 /* close the handle no matter what happened */
533 if (req->options & DUP_HANDLE_CLOSE_SOURCE)
Alexandre Julliardd549f692000-12-22 02:04:15 +0000534 {
Alexandre Julliard28418cc2006-11-02 20:48:19 +0100535 unsigned int err = get_error(); /* don't overwrite error from the above calls */
Alexandre Julliard8700c432006-11-02 20:52:05 +0100536 reply->closed = close_handle( src, req->src_handle );
Alexandre Julliard28418cc2006-11-02 20:48:19 +0100537 set_error( err );
Alexandre Julliardd549f692000-12-22 02:04:15 +0000538 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000539 release_object( src );
540 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000541}