66cac98e8aaab14d2d9b56712f7cdbea7db15794
[reactos.git] / reactos / ntoskrnl / ob / handle.c
1 /* $Id: handle.c,v 1.11 1999/08/29 06:59:11 ea Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/handle.c
6 * PURPOSE: Managing handles
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * REVISION HISTORY:
9 * 17/06/98: Created
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <windows.h>
15 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
17 #include <string.h>
18 #include <internal/string.h>
19 #include <internal/ps.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 /* TYPES *******************************************************************/
25
26 #define HANDLE_BLOCK_ENTRIES ((PAGESIZE-sizeof(LIST_ENTRY))/sizeof(HANDLE_REP))
27
28 /*
29 * PURPOSE: Defines a page's worth of handles
30 */
31 typedef struct
32 {
33 LIST_ENTRY entry;
34 HANDLE_REP handles[HANDLE_BLOCK_ENTRIES];
35 } HANDLE_BLOCK;
36
37 /* FUNCTIONS ***************************************************************/
38
39
40 static
41 PHANDLE_REP
42 ObpGetObjectByHandle(PEPROCESS Process,
43 HANDLE h)
44 /*
45 * FUNCTION: Get the data structure for a handle
46 * ARGUMENTS:
47 * Process = Process to get the handle for
48 * h = Handle
49 * ARGUMENTS: A pointer to the information about the handle on success,
50 * NULL on failure
51 */
52 {
53 PLIST_ENTRY current;
54 unsigned int handle = ((unsigned int)h) - 1;
55 unsigned int count=handle/HANDLE_BLOCK_ENTRIES;
56 HANDLE_BLOCK* blk = NULL;
57 unsigned int i;
58
59 DPRINT("ObpGetObjectByHandle(Process %x, h %x)\n",Process,h);
60
61 current = Process->Pcb.HandleTable.ListHead.Flink;
62 DPRINT("current %x\n",current);
63
64 for (i=0;i<count;i++)
65 {
66 current = current->Flink;
67 if (current == (&(Process->Pcb.HandleTable.ListHead)))
68 {
69 return(NULL);
70 }
71 }
72
73 blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
74 return(&(blk->handles[handle%HANDLE_BLOCK_ENTRIES]));
75 }
76
77
78 NTSTATUS
79 STDCALL
80 NtDuplicateObject (
81 IN HANDLE SourceProcessHandle,
82 IN PHANDLE SourceHandle,
83 IN HANDLE TargetProcessHandle,
84 OUT PHANDLE TargetHandle,
85 IN ACCESS_MASK DesiredAccess,
86 IN BOOLEAN InheritHandle,
87 ULONG Options
88 )
89 /*
90 * FUNCTION: Copies a handle from one process space to another
91 * ARGUMENTS:
92 * SourceProcessHandle = The source process owning the handle. The
93 * source process should have opened
94 * the SourceHandle with PROCESS_DUP_HANDLE
95 * access.
96 * SourceHandle = The handle to the object.
97 * TargetProcessHandle = The destination process owning the handle
98 * TargetHandle (OUT) = Caller should supply storage for the
99 * duplicated handle.
100 * DesiredAccess = The desired access to the handle.
101 * InheritHandle = Indicates wheter the new handle will be inheritable
102 * or not.
103 * Options = Specifies special actions upon duplicating the handle.
104 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
105 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
106 * that the source handle should be closed after duplicating.
107 * DUPLICATE_SAME_ACCESS specifies to ignore the
108 * DesiredAccess paramter and just grant the same access to
109 * the new handle.
110 * RETURNS: Status
111 * REMARKS: This function maps to the win32 DuplicateHandle.
112 */
113 {
114 PEPROCESS SourceProcess;
115 PEPROCESS TargetProcess;
116 PHANDLE_REP SourceHandleRep;
117
118 ASSERT_IRQL(PASSIVE_LEVEL);
119
120 ObReferenceObjectByHandle(SourceProcessHandle,
121 PROCESS_DUP_HANDLE,
122 NULL,
123 UserMode,
124 (PVOID*)&SourceProcess,
125 NULL);
126 ObReferenceObjectByHandle(TargetProcessHandle,
127 PROCESS_DUP_HANDLE,
128 NULL,
129 UserMode,
130 (PVOID*)&TargetProcess,
131 NULL);
132
133 SourceHandleRep = ObpGetObjectByHandle(SourceProcess,
134 *SourceHandle);
135
136 if (Options & DUPLICATE_SAME_ACCESS)
137 {
138 DesiredAccess = SourceHandleRep->GrantedAccess;
139 }
140
141 ObCreateHandle(TargetProcess,
142 SourceHandleRep->ObjectBody,
143 DesiredAccess,
144 InheritHandle,
145 TargetHandle);
146
147 if (Options & DUPLICATE_CLOSE_SOURCE)
148 {
149 ZwClose(*SourceHandle);
150 }
151
152 ObDereferenceObject(TargetProcess);
153 ObDereferenceObject(SourceProcess);
154
155 return(STATUS_SUCCESS);
156 }
157
158
159 VOID
160 ObDeleteHandleTable(PEPROCESS Process)
161 /*
162 * FUNCTION: Deletes the handle table associated with a process
163 */
164 {
165 PLIST_ENTRY current = NULL;
166 ULONG i;
167 PHANDLE_TABLE HandleTable = NULL;
168
169 HandleTable = &Process->Pcb.HandleTable;
170 current = RemoveHeadList(&HandleTable->ListHead);
171
172 while (current!=NULL)
173 {
174 HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
175 HANDLE_BLOCK,
176 entry);
177
178 /*
179 * Deference every handle in block
180 */
181 for (i=0;i<HANDLE_BLOCK_ENTRIES;i++)
182 {
183 if (HandleBlock->handles[i].ObjectBody != NULL)
184 {
185 ObDereferenceObject(HandleBlock->handles[i].ObjectBody);
186 }
187 }
188
189 ExFreePool(HandleBlock);
190
191 current = RemoveHeadList(&HandleTable->ListHead);
192 }
193 }
194
195
196 VOID
197 ObCreateHandleTable(PEPROCESS Parent,
198 BOOLEAN Inherit,
199 PEPROCESS Process)
200 /*
201 * FUNCTION: Creates a handle table for a process
202 * ARGUMENTS:
203 * Parent = Parent process (or NULL if this is the first process)
204 * Inherit = True if the process should inherit its parent's handles
205 * Process = Process whose handle table is to be created
206 */
207 {
208 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
209 Parent,Inherit,Process);
210
211 InitializeListHead(&(Process->Pcb.HandleTable.ListHead));
212 KeInitializeSpinLock(&(Process->Pcb.HandleTable.ListLock));
213
214 if (Parent != NULL)
215 {
216 }
217 }
218
219
220 VOID
221 ObDeleteHandle(HANDLE Handle)
222 {
223 PHANDLE_REP Rep;
224
225 DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
226
227 Rep = ObpGetObjectByHandle(PsGetCurrentProcess(),Handle);
228 Rep->ObjectBody=NULL;
229 DPRINT("Finished ObDeleteHandle()\n");
230 }
231
232
233 NTSTATUS
234 ObCreateHandle(PEPROCESS Process,
235 PVOID ObjectBody,
236 ACCESS_MASK GrantedAccess,
237 BOOLEAN Inherit,
238 PHANDLE HandleReturn)
239 /*
240 * FUNCTION: Add a handle referencing an object
241 * ARGUMENTS:
242 * obj = Object body that the handle should refer to
243 * RETURNS: The created handle
244 * NOTE: THe handle is valid only in the context of the current process
245 */
246 {
247 LIST_ENTRY* current;
248 unsigned int handle=1;
249 unsigned int i;
250 HANDLE_BLOCK* new_blk = NULL;
251 PHANDLE_TABLE HandleTable;
252 KIRQL oldlvl;
253
254 DPRINT("ObAddHandle(Process %x, obj %x)\n",Process,ObjectBody);
255
256 HandleTable = &Process->Pcb.HandleTable;
257
258 KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
259 current = HandleTable->ListHead.Flink;
260
261 /*
262 * Scan through the currently allocated handle blocks looking for a free
263 * slot
264 */
265 while (current != (&HandleTable->ListHead))
266 {
267 HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
268
269 DPRINT("Current %x\n",current);
270
271 for (i=0;i<HANDLE_BLOCK_ENTRIES;i++)
272 {
273 DPRINT("Considering slot %d containing %x\n",i,blk->handles[i]);
274 if (blk->handles[i].ObjectBody==NULL)
275 {
276 blk->handles[i].ObjectBody = ObjectBody;
277 blk->handles[i].GrantedAccess = GrantedAccess;
278 blk->handles[i].Inherit = Inherit;
279 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
280 *HandleReturn = (HANDLE)(handle + i);
281 return(STATUS_SUCCESS);
282 }
283 }
284
285 handle = handle + HANDLE_BLOCK_ENTRIES;
286 current = current->Flink;
287 }
288
289 /*
290 * Add a new handle block to the end of the list
291 */
292 new_blk = (HANDLE_BLOCK *)ExAllocatePool(NonPagedPool,sizeof(HANDLE_BLOCK));
293 memset(new_blk,0,sizeof(HANDLE_BLOCK));
294 InsertTailList(&(Process->Pcb.HandleTable.ListHead),
295 &new_blk->entry);
296 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
297 new_blk->handles[0].ObjectBody = ObjectBody;
298 new_blk->handles[0].GrantedAccess = GrantedAccess;
299 new_blk->handles[0].Inherit = Inherit;
300 *HandleReturn = (HANDLE)handle;
301 return(STATUS_SUCCESS);
302 }
303
304
305 NTSTATUS
306 ObReferenceObjectByHandle(HANDLE Handle,
307 ACCESS_MASK DesiredAccess,
308 POBJECT_TYPE ObjectType,
309 KPROCESSOR_MODE AccessMode,
310 PVOID* Object,
311 POBJECT_HANDLE_INFORMATION
312 HandleInformationPtr)
313 /*
314 * FUNCTION: Increments the reference count for an object and returns a
315 * pointer to its body
316 * ARGUMENTS:
317 * Handle = Handle for the object
318 * DesiredAccess = Desired access to the object
319 * ObjectType
320 * AccessMode
321 * Object (OUT) = Points to the object body on return
322 * HandleInformation (OUT) = Contains information about the handle
323 * on return
324 * RETURNS: Status
325 */
326 {
327 PHANDLE_REP HandleRep;
328 POBJECT_HEADER ObjectHeader;
329
330 ASSERT_IRQL(PASSIVE_LEVEL);
331
332 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
333 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
334 ObjectType,AccessMode,Object);
335
336
337
338 if (Handle == NtCurrentProcess() &&
339 (ObjectType == PsProcessType || ObjectType == NULL))
340 {
341 BODY_TO_HEADER(PsGetCurrentProcess())->RefCount++;
342 *Object = PsGetCurrentProcess();
343 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
344 return(STATUS_SUCCESS);
345 }
346 else if (Handle == NtCurrentProcess())
347 {
348 CHECKPOINT;
349 return(STATUS_OBJECT_TYPE_MISMATCH);
350 }
351 if (Handle == NtCurrentThread() &&
352 (ObjectType == PsThreadType || ObjectType == NULL))
353 {
354 BODY_TO_HEADER(PsGetCurrentThread())->RefCount++;
355 *Object = PsGetCurrentThread();
356 CHECKPOINT;
357 return(STATUS_SUCCESS);
358 }
359 else if (Handle == NtCurrentThread())
360 {
361 CHECKPOINT;
362 return(STATUS_OBJECT_TYPE_MISMATCH);
363 }
364
365 HandleRep = ObpGetObjectByHandle(PsGetCurrentProcess(),
366 Handle);
367 if (HandleRep == NULL || HandleRep->ObjectBody == NULL)
368 {
369 CHECKPOINT;
370 return(STATUS_INVALID_HANDLE);
371 }
372
373 ObjectHeader = BODY_TO_HEADER(HandleRep->ObjectBody);
374
375 if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType)
376 {
377 CHECKPOINT;
378 return(STATUS_OBJECT_TYPE_MISMATCH);
379 }
380
381 if (!(HandleRep->GrantedAccess & DesiredAccess))
382 {
383 CHECKPOINT;
384 return(STATUS_ACCESS_DENIED);
385 }
386
387 ObjectHeader->RefCount++;
388
389 *Object = HandleRep->ObjectBody;
390
391 CHECKPOINT;
392 return(STATUS_SUCCESS);
393 }
394
395
396 /**********************************************************************
397 * NAME EXPORTED
398 * NtClose
399 *
400 * DESCRIPTION
401 * Closes a handle reference to an object.
402 *
403 * ARGUMENTS
404 * Handle
405 * Handle to close.
406 *
407 * RETURN VALUE
408 * Status.
409 */
410 NTSTATUS
411 STDCALL
412 NtClose(HANDLE Handle)
413 {
414 PVOID ObjectBody;
415 POBJECT_HEADER Header;
416 PHANDLE_REP HandleRep;
417
418 assert_irql(PASSIVE_LEVEL);
419
420 DPRINT("NtClose(Handle %x)\n",Handle);
421
422 HandleRep = ObpGetObjectByHandle(
423 PsGetCurrentProcess(),
424 Handle
425 );
426 if (HandleRep == NULL)
427 {
428 return STATUS_INVALID_HANDLE;
429 }
430 ObjectBody = HandleRep->ObjectBody;
431
432 HandleRep->ObjectBody = NULL;
433
434 Header = BODY_TO_HEADER(ObjectBody);
435
436 Header->RefCount++;
437 Header->HandleCount--;
438
439 if ( (Header->ObjectType != NULL)
440 && (Header->ObjectType->Close != NULL)
441 )
442 {
443 Header->ObjectType->Close(
444 ObjectBody,
445 Header->HandleCount
446 );
447 }
448
449 Header->RefCount--;
450
451 ObPerformRetentionChecks(Header);
452
453 return STATUS_SUCCESS;
454 }
455
456
457 /* EOF */