Make dump functions const.
[wine] / server / object.c
1 /*
2  * Server-side objects
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  *
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
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "winternl.h"
35
36 #include "file.h"
37 #include "thread.h"
38 #include "unicode.h"
39
40
41 struct object_name
42 {
43     struct list         entry;           /* entry in the hash list */
44     struct object      *obj;             /* object owning this name */
45     struct object      *parent;          /* parent object */
46     size_t              len;             /* name length in bytes */
47     WCHAR               name[1];
48 };
49
50 struct namespace
51 {
52     unsigned int        hash_size;       /* size of hash table */
53     struct list         names[1];        /* array of hash entry lists */
54 };
55
56
57 #ifdef DEBUG_OBJECTS
58 static struct list object_list = LIST_INIT(object_list);
59
60 void dump_objects(void)
61 {
62     struct list *p;
63
64     LIST_FOR_EACH( p, &object_list )
65     {
66         struct object *ptr = LIST_ENTRY( p, struct object, obj_list );
67         fprintf( stderr, "%p:%d: ", ptr, ptr->refcount );
68         ptr->ops->dump( ptr, 1 );
69     }
70 }
71 #endif
72
73 /*****************************************************************/
74
75 /* malloc replacement */
76 void *mem_alloc( size_t size )
77 {
78     void *ptr = malloc( size );
79     if (ptr) memset( ptr, 0x55, size );
80     else set_error( STATUS_NO_MEMORY );
81     return ptr;
82 }
83
84 /* duplicate a block of memory */
85 void *memdup( const void *data, size_t len )
86 {
87     void *ptr = malloc( len );
88     if (ptr) memcpy( ptr, data, len );
89     else set_error( STATUS_NO_MEMORY );
90     return ptr;
91 }
92
93
94 /*****************************************************************/
95
96 static int get_name_hash( const struct namespace *namespace, const WCHAR *name, size_t len )
97 {
98     WCHAR hash = 0;
99     len /= sizeof(WCHAR);
100     while (len--) hash ^= tolowerW(*name++);
101     return hash % namespace->hash_size;
102 }
103
104 /* allocate a name for an object */
105 static struct object_name *alloc_name( const struct unicode_str *name )
106 {
107     struct object_name *ptr;
108
109     if ((ptr = mem_alloc( sizeof(*ptr) + name->len - sizeof(ptr->name) )))
110     {
111         ptr->len = name->len;
112         ptr->parent = NULL;
113         memcpy( ptr->name, name->str, name->len );
114     }
115     return ptr;
116 }
117
118 /* free the name of an object */
119 static void free_name( struct object *obj )
120 {
121     struct object_name *ptr = obj->name;
122     list_remove( &ptr->entry );
123     if (ptr->parent) release_object( ptr->parent );
124     free( ptr );
125 }
126
127 /* set the name of an existing object */
128 static void set_object_name( struct namespace *namespace,
129                              struct object *obj, struct object_name *ptr )
130 {
131     int hash = get_name_hash( namespace, ptr->name, ptr->len );
132
133     list_add_head( &namespace->names[hash], &ptr->entry );
134     ptr->obj = obj;
135     obj->name = ptr;
136 }
137
138 /* get the name of an existing object */
139 const WCHAR *get_object_name( struct object *obj, size_t *len )
140 {
141     struct object_name *ptr = obj->name;
142     if (!ptr) return NULL;
143     *len = ptr->len;
144     return ptr->name;
145 }
146
147 /* allocate and initialize an object */
148 void *alloc_object( const struct object_ops *ops )
149 {
150     struct object *obj = mem_alloc( ops->size );
151     if (obj)
152     {
153         obj->refcount = 1;
154         obj->ops      = ops;
155         obj->name     = NULL;
156         list_init( &obj->wait_queue );
157 #ifdef DEBUG_OBJECTS
158         list_add_head( &object_list, &obj->obj_list );
159 #endif
160         return obj;
161     }
162     return NULL;
163 }
164
165 void *create_object( struct namespace *namespace, const struct object_ops *ops,
166                      const struct unicode_str *name, struct object *parent )
167 {
168     struct object *obj;
169     struct object_name *name_ptr;
170
171     if (!(name_ptr = alloc_name( name ))) return NULL;
172     if ((obj = alloc_object( ops )))
173     {
174         set_object_name( namespace, obj, name_ptr );
175         if (parent) name_ptr->parent = grab_object( parent );
176     }
177     else
178         free( name_ptr );
179     return obj;
180 }
181
182 void *create_named_object( struct namespace *namespace, const struct object_ops *ops,
183                            const struct unicode_str *name, unsigned int attributes )
184 {
185     struct object *obj;
186
187     if (!name || !name->len) return alloc_object( ops );
188
189     if ((obj = find_object( namespace, name, attributes )))
190     {
191         if (attributes & OBJ_OPENIF && obj->ops == ops)
192             set_error( STATUS_OBJECT_NAME_EXISTS );
193         else
194         {
195             release_object( obj );
196             obj = NULL;
197             if (attributes & OBJ_OPENIF)
198                 set_error( STATUS_OBJECT_TYPE_MISMATCH );
199             else
200                 set_error( STATUS_OBJECT_NAME_COLLISION );
201         }
202         return obj;
203     }
204     if ((obj = create_object( namespace, ops, name, NULL ))) clear_error();
205     return obj;
206 }
207
208 /* dump the name of an object to stderr */
209 void dump_object_name( struct object *obj )
210 {
211     if (!obj->name) fprintf( stderr, "name=\"\"" );
212     else
213     {
214         fprintf( stderr, "name=L\"" );
215         dump_strW( obj->name->name, obj->name->len/sizeof(WCHAR), stderr, "\"\"" );
216         fputc( '\"', stderr );
217     }
218 }
219
220 /* grab an object (i.e. increment its refcount) and return the object */
221 struct object *grab_object( void *ptr )
222 {
223     struct object *obj = (struct object *)ptr;
224     assert( obj->refcount < INT_MAX );
225     obj->refcount++;
226     return obj;
227 }
228
229 /* release an object (i.e. decrement its refcount) */
230 void release_object( void *ptr )
231 {
232     struct object *obj = (struct object *)ptr;
233     assert( obj->refcount );
234     if (!--obj->refcount)
235     {
236         /* if the refcount is 0, nobody can be in the wait queue */
237         assert( list_empty( &obj->wait_queue ));
238         obj->ops->destroy( obj );
239         if (obj->name) free_name( obj );
240 #ifdef DEBUG_OBJECTS
241         list_remove( &obj->obj_list );
242         memset( obj, 0xaa, obj->ops->size );
243 #endif
244         free( obj );
245     }
246 }
247
248 /* find an object by its name; the refcount is incremented */
249 struct object *find_object( const struct namespace *namespace, const struct unicode_str *name,
250                             unsigned int attributes )
251 {
252     const struct list *list, *p;
253
254     if (!name || !name->len) return NULL;
255
256     list = &namespace->names[ get_name_hash( namespace, name->str, name->len ) ];
257     LIST_FOR_EACH( p, list )
258     {
259         const struct object_name *ptr = LIST_ENTRY( p, const struct object_name, entry );
260         if (ptr->len != name->len) continue;
261         if (attributes & OBJ_CASE_INSENSITIVE)
262         {
263             if (!strncmpiW( ptr->name, name->str, name->len/sizeof(WCHAR) ))
264                 return grab_object( ptr->obj );
265         }
266         else
267         {
268             if (!memcmp( ptr->name, name->str, name->len ))
269                 return grab_object( ptr->obj );
270         }
271     }
272     return NULL;
273 }
274
275 /* allocate a namespace */
276 struct namespace *create_namespace( unsigned int hash_size )
277 {
278     struct namespace *namespace;
279     unsigned int i;
280
281     namespace = mem_alloc( sizeof(*namespace) + (hash_size - 1) * sizeof(namespace->names[0]) );
282     if (namespace)
283     {
284         namespace->hash_size      = hash_size;
285         for (i = 0; i < hash_size; i++) list_init( &namespace->names[i] );
286     }
287     return namespace;
288 }
289
290 /* functions for unimplemented/default object operations */
291
292 int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
293 {
294     set_error( STATUS_OBJECT_TYPE_MISMATCH );
295     return 0;
296 }
297
298 int no_satisfied( struct object *obj, struct thread *thread )
299 {
300     return 0;  /* not abandoned */
301 }
302
303 int no_signal( struct object *obj, unsigned int access )
304 {
305     set_error( STATUS_OBJECT_TYPE_MISMATCH );
306     return 0;
307 }
308
309 struct fd *no_get_fd( struct object *obj )
310 {
311     set_error( STATUS_OBJECT_TYPE_MISMATCH );
312     return NULL;
313 }
314
315 struct object *no_lookup_name( struct object *obj, struct unicode_str *name,
316                                unsigned int attr )
317 {
318     return NULL;
319 }
320
321 int no_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
322 {
323     return 1;  /* ok to close */
324 }
325
326 void no_destroy( struct object *obj )
327 {
328 }