New stubs: SHGetFileInfo32W, ReadCabinetState, WriteCabinetState, IsUserAdmin.
[wine] / scheduler / k32obj.c
1 /*
2  * KERNEL32 objects
3  *
4  * Copyright 1996 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include "winerror.h"
9 #include "k32obj.h"
10 #include "heap.h"
11 #include "process.h"
12
13
14 /* The declarations are here to avoid including a lot of unnecessary files */
15 extern const K32OBJ_OPS SEMAPHORE_Ops;
16 extern const K32OBJ_OPS EVENT_Ops;
17 extern const K32OBJ_OPS MUTEX_Ops;
18 extern const K32OBJ_OPS CRITICAL_SECTION_Ops;
19 extern const K32OBJ_OPS PROCESS_Ops;
20 extern const K32OBJ_OPS THREAD_Ops;
21 extern const K32OBJ_OPS FILE_Ops;
22 extern const K32OBJ_OPS CHANGE_Ops;
23 extern const K32OBJ_OPS MEM_MAPPED_FILE_Ops;
24 extern const K32OBJ_OPS DEVICE_Ops;
25 extern const K32OBJ_OPS CONSOLE_Ops;
26
27 static const K32OBJ_OPS K32OBJ_NullOps =
28 {
29     NULL,    /* signaled */
30     NULL,    /* satisfied */
31     NULL,    /* add_wait */
32     NULL,    /* remove_wait */
33     NULL,    /* read */
34     NULL,    /* write */
35     NULL     /* destroy */
36 };
37
38 const K32OBJ_OPS * const K32OBJ_Ops[K32OBJ_NBOBJECTS] =
39 {
40     NULL,
41     &SEMAPHORE_Ops,         /* K32OBJ_SEMAPHORE */
42     &EVENT_Ops,             /* K32OBJ_EVENT */
43     &MUTEX_Ops,             /* K32OBJ_MUTEX */
44     &CRITICAL_SECTION_Ops,  /* K32OBJ_CRITICAL_SECTION */
45     &PROCESS_Ops,           /* K32OBJ_PROCESS */
46     &THREAD_Ops,            /* K32OBJ_THREAD */
47     &FILE_Ops,              /* K32OBJ_FILE */
48     &CHANGE_Ops,            /* K32OBJ_CHANGE */
49     &CONSOLE_Ops,           /* K32OBJ_CONSOLE */
50     &K32OBJ_NullOps,        /* K32OBJ_SCREEN_BUFFER */
51     &MEM_MAPPED_FILE_Ops,   /* K32OBJ_MEM_MAPPED_FILE */
52     &K32OBJ_NullOps,        /* K32OBJ_SERIAL */
53     &DEVICE_Ops,            /* K32OBJ_DEVICE_IOCTL */
54     &K32OBJ_NullOps,        /* K32OBJ_PIPE */
55     &K32OBJ_NullOps,        /* K32OBJ_MAILSLOT */
56     &K32OBJ_NullOps,        /* K32OBJ_TOOLHELP_SNAPSHOT */
57     &K32OBJ_NullOps         /* K32OBJ_SOCKET */
58 };
59
60 typedef struct _NE
61 {
62     struct _NE *next;
63     K32OBJ     *obj;
64     UINT32      len;
65     char        name[1];
66 } NAME_ENTRY;
67
68 static NAME_ENTRY *K32OBJ_FirstEntry = NULL;
69
70
71 /***********************************************************************
72  *           K32OBJ_IncCount
73  */
74 void K32OBJ_IncCount( K32OBJ *ptr )
75 {
76     assert( ptr->type && ((unsigned)ptr->type < K32OBJ_NBOBJECTS) );
77     SYSTEM_LOCK();
78     ptr->refcount++;
79     SYSTEM_UNLOCK();
80     assert( ptr->refcount > 0 );  /* No wrap-around allowed */
81 }
82
83
84 /***********************************************************************
85  *           K32OBJ_DecCount
86  */
87 void K32OBJ_DecCount( K32OBJ *ptr )
88 {
89     NAME_ENTRY **pptr;
90
91     assert( ptr->type && ((unsigned)ptr->type < K32OBJ_NBOBJECTS) );
92     assert( ptr->refcount > 0 );
93     SYSTEM_LOCK();
94     if (--ptr->refcount)
95     {
96         SYSTEM_UNLOCK();
97         return;
98     }
99
100     /* Check if the object has a name entry and free it */
101
102     pptr = &K32OBJ_FirstEntry;
103     while (*pptr && ((*pptr)->obj != ptr)) pptr = &(*pptr)->next;
104     if (*pptr)
105     {
106         NAME_ENTRY *entry = *pptr;
107         *pptr = entry->next;
108         HeapFree( SystemHeap, 0, entry );
109     }
110
111     /* Free the object */
112
113     if (K32OBJ_Ops[ptr->type]->destroy) K32OBJ_Ops[ptr->type]->destroy( ptr );
114     SYSTEM_UNLOCK();
115 }
116
117
118 /***********************************************************************
119  *           K32OBJ_IsValid
120  *
121  * Check if a pointer is a valid kernel object
122  */
123 BOOL32 K32OBJ_IsValid( K32OBJ *ptr, K32OBJ_TYPE type )
124 {
125     if (IsBadReadPtr32( ptr, sizeof(*ptr) )) return FALSE;
126     return (ptr->type == type);
127 }
128
129
130 /***********************************************************************
131  *           K32OBJ_AddName
132  *
133  * Add a name entry for an object. We don't check for duplicates here.
134  * FIXME: should use some sort of hashing.
135  */
136 BOOL32 K32OBJ_AddName( K32OBJ *obj, LPCSTR name )
137 {
138     NAME_ENTRY *entry;
139     UINT32 len;
140
141     if (!name) return TRUE;  /* Anonymous object */
142     len = strlen( name );
143     SYSTEM_LOCK();
144     if (!(entry = HeapAlloc( SystemHeap, 0, sizeof(NAME_ENTRY) + len )))
145     {
146         SYSTEM_UNLOCK();
147         SetLastError( ERROR_OUTOFMEMORY );
148         return FALSE;
149     }
150     entry->next = K32OBJ_FirstEntry;
151     entry->obj  = obj;
152     entry->len  = len;
153     lstrcpy32A( entry->name, name );
154     K32OBJ_FirstEntry = entry;
155     SYSTEM_UNLOCK();
156     return TRUE;
157 }
158
159
160 /***********************************************************************
161  *           K32OBJ_Create
162  *
163  * Create a named kernel object.
164  * Returns NULL if there was an error _or_ if the object already existed.
165  * The refcount of the object must be decremented once it is initialized.
166  */
167 K32OBJ *K32OBJ_Create( K32OBJ_TYPE type, DWORD size, LPCSTR name, int server_handle,
168                        DWORD access, SECURITY_ATTRIBUTES *sa, HANDLE32 *handle)
169 {
170     BOOL32 inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
171
172     /* Check if the name already exists */
173
174     K32OBJ *obj = K32OBJ_FindName( name );
175     if (obj)
176     {
177         if (obj->type == type)
178         {
179             SetLastError( ERROR_ALREADY_EXISTS );
180             *handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, server_handle );
181         }
182         else
183         {
184             SetLastError( ERROR_DUP_NAME );
185             *handle = INVALID_HANDLE_VALUE32;
186             if (server_handle != -1) CLIENT_CloseHandle( server_handle );
187         }
188         K32OBJ_DecCount( obj );
189         return NULL;
190     }
191
192     /* Create the object */
193
194     SYSTEM_LOCK();
195     if (!(obj = HeapAlloc( SystemHeap, 0, size )))
196     {
197         SYSTEM_UNLOCK();
198         *handle = INVALID_HANDLE_VALUE32;
199         if (server_handle != -1) CLIENT_CloseHandle( server_handle );
200         return NULL;
201     }
202     obj->type     = type;
203     obj->refcount = 1;
204
205     /* Add a name for it */
206
207     if (!K32OBJ_AddName( obj, name ))
208     {
209         /* Don't call the destroy function, as the object wasn't
210          * initialized properly */
211         HeapFree( SystemHeap, 0, obj );
212         SYSTEM_UNLOCK();
213         *handle = INVALID_HANDLE_VALUE32;
214         if (server_handle != -1) CLIENT_CloseHandle( server_handle );
215         return NULL;
216     }
217
218     /* Allocate a handle */
219
220     *handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, server_handle );
221     SYSTEM_UNLOCK();
222     return obj;
223 }
224
225
226 /***********************************************************************
227  *           K32OBJ_FindName
228  *
229  * Find the object referenced by a given name.
230  * The reference count is incremented.
231  */
232 K32OBJ *K32OBJ_FindName( LPCSTR name )
233 {
234     NAME_ENTRY *entry;
235     UINT32 len;
236
237     if (!name) return NULL;  /* Anonymous object */
238     len = strlen( name );
239     SYSTEM_LOCK();
240     entry = K32OBJ_FirstEntry;
241     while (entry)
242     {
243         if ((len == entry->len) && !strcmp( name, entry->name))
244         {
245             K32OBJ *obj = entry->obj;
246             K32OBJ_IncCount( obj );
247             SYSTEM_UNLOCK();
248             return entry->obj;
249         }
250         entry = entry->next;
251     }
252     SYSTEM_UNLOCK();
253     return NULL;
254 }
255
256
257 /***********************************************************************
258  *           K32OBJ_FindNameType
259  *
260  * Find an object by name and check its type.
261  * The reference count is incremented.
262  */
263 K32OBJ *K32OBJ_FindNameType( LPCSTR name, K32OBJ_TYPE type )
264 {
265     K32OBJ *obj = K32OBJ_FindName( name );
266     if (!obj) return NULL;
267     if (obj->type == type) return obj;
268     SetLastError( ERROR_DUP_NAME );
269     K32OBJ_DecCount( obj );
270     return NULL;
271 }