1 /* $Id: handle.c,v 1.20 2000/04/03 21:54:40 dwelch Exp $
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)
12 /* INCLUDES ****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/ob.h>
17 #include <internal/string.h>
18 #include <internal/ps.h>
21 #include <internal/debug.h>
23 /* TYPES *******************************************************************/
25 #define HANDLE_BLOCK_ENTRIES ((PAGESIZE-sizeof(LIST_ENTRY))/sizeof(HANDLE_REP))
28 * PURPOSE: Defines a page's worth of handles
33 HANDLE_REP handles
[HANDLE_BLOCK_ENTRIES
];
34 } HANDLE_BLOCK
, *PHANDLE_BLOCK
;
36 /* FUNCTIONS ***************************************************************/
39 static PHANDLE_REP
ObpGetObjectByHandle(PHANDLE_TABLE HandleTable
, HANDLE h
)
41 * FUNCTION: Get the data structure for a handle
43 * Process = Process to get the handle for
45 * ARGUMENTS: A pointer to the information about the handle on success,
50 unsigned int handle
= (((unsigned int)h
) - 1) >> 2;
51 unsigned int count
=handle
/HANDLE_BLOCK_ENTRIES
;
52 HANDLE_BLOCK
* blk
= NULL
;
55 DPRINT("ObpGetObjectByHandle(HandleTable %x, h %x)\n",HandleTable
,h
);
57 current
= HandleTable
->ListHead
.Flink
;
58 DPRINT("current %x\n",current
);
62 current
= current
->Flink
;
63 if (current
== (&(HandleTable
->ListHead
)))
69 blk
= CONTAINING_RECORD(current
,HANDLE_BLOCK
,entry
);
70 return(&(blk
->handles
[handle
%HANDLE_BLOCK_ENTRIES
]));
74 NTSTATUS STDCALL
NtDuplicateObject (IN HANDLE SourceProcessHandle
,
75 IN PHANDLE SourceHandle
,
76 IN HANDLE TargetProcessHandle
,
77 OUT PHANDLE TargetHandle
,
78 IN ACCESS_MASK DesiredAccess
,
79 IN BOOLEAN InheritHandle
,
82 * FUNCTION: Copies a handle from one process space to another
84 * SourceProcessHandle = The source process owning the handle. The
85 * source process should have opened
86 * the SourceHandle with PROCESS_DUP_HANDLE
88 * SourceHandle = The handle to the object.
89 * TargetProcessHandle = The destination process owning the handle
90 * TargetHandle (OUT) = Caller should supply storage for the
92 * DesiredAccess = The desired access to the handle.
93 * InheritHandle = Indicates wheter the new handle will be inheritable
95 * Options = Specifies special actions upon duplicating the handle.
96 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
97 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
98 * that the source handle should be closed after duplicating.
99 * DUPLICATE_SAME_ACCESS specifies to ignore the
100 * DesiredAccess paramter and just grant the same access to
103 * REMARKS: This function maps to the win32 DuplicateHandle.
106 PEPROCESS SourceProcess
;
107 PEPROCESS TargetProcess
;
108 PHANDLE_REP SourceHandleRep
;
112 ASSERT_IRQL(PASSIVE_LEVEL
);
114 ObReferenceObjectByHandle(SourceProcessHandle
,
118 (PVOID
*)&SourceProcess
,
120 ObReferenceObjectByHandle(TargetProcessHandle
,
124 (PVOID
*)&TargetProcess
,
127 KeAcquireSpinLock(&SourceProcess
->Pcb
.HandleTable
.ListLock
, &oldIrql
);
128 SourceHandleRep
= ObpGetObjectByHandle(&SourceProcess
->Pcb
.HandleTable
,
130 if (SourceHandleRep
== NULL
)
132 KeReleaseSpinLock(&SourceProcess
->Pcb
.HandleTable
.ListLock
, oldIrql
);
133 ObDereferenceObject(SourceProcess
);
134 ObDereferenceObject(TargetProcess
);
135 return(STATUS_INVALID_HANDLE
);
137 ObjectBody
= SourceHandleRep
->ObjectBody
;
138 ObReferenceObjectByPointer(ObjectBody
,
143 if (Options
& DUPLICATE_SAME_ACCESS
)
145 DesiredAccess
= SourceHandleRep
->GrantedAccess
;
148 KeReleaseSpinLock(&SourceProcess
->Pcb
.HandleTable
.ListLock
, oldIrql
);
150 ObCreateHandle(TargetProcess
,
156 if (Options
& DUPLICATE_CLOSE_SOURCE
)
158 ZwClose(*SourceHandle
);
161 ObDereferenceObject(TargetProcess
);
162 ObDereferenceObject(SourceProcess
);
163 ObDereferenceObject(ObjectBody
);
165 return(STATUS_SUCCESS
);
168 VOID
ObCloseAllHandles(PEPROCESS Process
)
171 PHANDLE_TABLE HandleTable
;
172 PLIST_ENTRY current_entry
;
173 PHANDLE_BLOCK current
;
177 DPRINT("ObCloseAllHandles(Process %x)\n", Process
);
179 HandleTable
= &Process
->Pcb
.HandleTable
;
181 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
183 current_entry
= HandleTable
->ListHead
.Flink
;
185 while (current_entry
!= &HandleTable
->ListHead
)
187 current
= CONTAINING_RECORD(current_entry
, HANDLE_BLOCK
, entry
);
189 for (i
= 0; i
< HANDLE_BLOCK_ENTRIES
; i
++)
191 ObjectBody
= current
->handles
[i
].ObjectBody
;
193 if (ObjectBody
!= NULL
)
195 POBJECT_HEADER Header
= BODY_TO_HEADER(ObjectBody
);
197 if (Header
->ObjectType
== PsProcessType
||
198 Header
->ObjectType
== PsThreadType
)
200 DPRINT("Deleting handle to %x\n", ObjectBody
);
203 ObReferenceObjectByPointer(ObjectBody
,
207 Header
->HandleCount
--;
208 current
->handles
[i
].ObjectBody
= NULL
;
210 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
212 if ((Header
->ObjectType
!= NULL
) &&
213 (Header
->ObjectType
->Close
!= NULL
))
215 Header
->ObjectType
->Close(ObjectBody
,
216 Header
->HandleCount
);
219 ObDereferenceObject(ObjectBody
);
220 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
221 current_entry
= &HandleTable
->ListHead
;
226 current_entry
= current_entry
->Flink
;
228 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
229 DPRINT("ObCloseAllHandles() finished\n");
230 DPRINT("Type %x\n", BODY_TO_HEADER(Process
)->ObjectType
);
233 VOID
ObDeleteHandleTable(PEPROCESS Process
)
235 * FUNCTION: Deletes the handle table associated with a process
238 PLIST_ENTRY current
= NULL
;
239 PHANDLE_TABLE HandleTable
= NULL
;
241 ObCloseAllHandles(Process
);
243 HandleTable
= &Process
->Pcb
.HandleTable
;
244 current
= RemoveHeadList(&HandleTable
->ListHead
);
246 while (current
!= &HandleTable
->ListHead
)
248 HANDLE_BLOCK
* HandleBlock
= CONTAINING_RECORD(current
,
251 DPRINT("Freeing %x\n", HandleBlock
);
252 ExFreePool(HandleBlock
);
254 current
= RemoveHeadList(&HandleTable
->ListHead
);
259 VOID
ObCreateHandleTable(PEPROCESS Parent
,
263 * FUNCTION: Creates a handle table for a process
265 * Parent = Parent process (or NULL if this is the first process)
266 * Inherit = True if the process should inherit its parent's handles
267 * Process = Process whose handle table is to be created
270 PHANDLE_TABLE ParentHandleTable
;
272 PLIST_ENTRY parent_current
;
275 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
276 Parent
,Inherit
,Process
);
278 InitializeListHead(&(Process
->Pcb
.HandleTable
.ListHead
));
279 KeInitializeSpinLock(&(Process
->Pcb
.HandleTable
.ListLock
));
283 ParentHandleTable
= &Parent
->Pcb
.HandleTable
;
285 KeAcquireSpinLock(&Parent
->Pcb
.HandleTable
.ListLock
, &oldIrql
);
287 parent_current
= ParentHandleTable
->ListHead
.Flink
;
289 while (parent_current
!= &ParentHandleTable
->ListHead
)
291 HANDLE_BLOCK
* current_block
= CONTAINING_RECORD(parent_current
,
296 for (i
=0; i
<HANDLE_BLOCK_ENTRIES
; i
++)
298 if (Inherit
|| current_block
->handles
[i
].Inherit
)
300 ObCreateHandle(Process
,
301 current_block
->handles
[i
].ObjectBody
,
302 current_block
->handles
[i
].GrantedAccess
,
303 current_block
->handles
[i
].Inherit
,
308 ObCreateHandle(Process
,
311 current_block
->handles
[i
].Inherit
,
316 parent_current
= parent_current
->Flink
;
319 KeReleaseSpinLock(&Parent
->Pcb
.HandleTable
.ListLock
, oldIrql
);
324 PVOID
ObDeleteHandle(PEPROCESS Process
, HANDLE Handle
)
329 PHANDLE_TABLE HandleTable
;
330 POBJECT_HEADER Header
;
332 DPRINT("ObDeleteHandle(Handle %x)\n",Handle
);
334 HandleTable
= &Process
->Pcb
.HandleTable
;
336 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldIrql
);
338 Rep
= ObpGetObjectByHandle(HandleTable
, Handle
);
339 ObjectBody
= Rep
->ObjectBody
;
340 Header
= BODY_TO_HEADER(ObjectBody
);
341 BODY_TO_HEADER(ObjectBody
)->HandleCount
--;
342 ObReferenceObjectByPointer(ObjectBody
,
346 Rep
->ObjectBody
= NULL
;
348 KeReleaseSpinLock(&HandleTable
->ListLock
, oldIrql
);
350 if ((Header
->ObjectType
!= NULL
) &&
351 (Header
->ObjectType
->Close
!= NULL
))
353 Header
->ObjectType
->Close(ObjectBody
, Header
->HandleCount
);
356 DPRINT("Finished ObDeleteHandle()\n");
361 NTSTATUS
ObCreateHandle(PEPROCESS Process
,
363 ACCESS_MASK GrantedAccess
,
365 PHANDLE HandleReturn
)
367 * FUNCTION: Add a handle referencing an object
369 * obj = Object body that the handle should refer to
370 * RETURNS: The created handle
371 * NOTE: THe handle is valid only in the context of the current process
375 unsigned int handle
=1;
377 HANDLE_BLOCK
* new_blk
= NULL
;
378 PHANDLE_TABLE HandleTable
;
381 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process
,ObjectBody
);
383 if (ObjectBody
!= NULL
)
385 BODY_TO_HEADER(ObjectBody
)->HandleCount
++;
388 HandleTable
= &Process
->Pcb
.HandleTable
;
390 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldlvl
);
391 current
= HandleTable
->ListHead
.Flink
;
394 * Scan through the currently allocated handle blocks looking for a free
397 while (current
!= (&HandleTable
->ListHead
))
399 HANDLE_BLOCK
* blk
= CONTAINING_RECORD(current
,HANDLE_BLOCK
,entry
);
401 DPRINT("Current %x\n",current
);
403 for (i
=0;i
<HANDLE_BLOCK_ENTRIES
;i
++)
405 DPRINT("Considering slot %d containing %x\n",i
,blk
->handles
[i
]);
406 if (blk
->handles
[i
].ObjectBody
==NULL
)
408 blk
->handles
[i
].ObjectBody
= ObjectBody
;
409 blk
->handles
[i
].GrantedAccess
= GrantedAccess
;
410 blk
->handles
[i
].Inherit
= Inherit
;
411 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
412 *HandleReturn
= (HANDLE
)((handle
+ i
) << 2);
413 return(STATUS_SUCCESS
);
417 handle
= handle
+ HANDLE_BLOCK_ENTRIES
;
418 current
= current
->Flink
;
422 * Add a new handle block to the end of the list
424 new_blk
= (HANDLE_BLOCK
*)ExAllocatePool(NonPagedPool
,sizeof(HANDLE_BLOCK
));
425 memset(new_blk
,0,sizeof(HANDLE_BLOCK
));
426 InsertTailList(&(Process
->Pcb
.HandleTable
.ListHead
),
428 KeReleaseSpinLock(&HandleTable
->ListLock
, oldlvl
);
429 new_blk
->handles
[0].ObjectBody
= ObjectBody
;
430 new_blk
->handles
[0].GrantedAccess
= GrantedAccess
;
431 new_blk
->handles
[0].Inherit
= Inherit
;
432 *HandleReturn
= (HANDLE
)(handle
<< 2);
433 return(STATUS_SUCCESS
);
437 NTSTATUS
ObReferenceObjectByHandle(HANDLE Handle
,
438 ACCESS_MASK DesiredAccess
,
439 POBJECT_TYPE ObjectType
,
440 KPROCESSOR_MODE AccessMode
,
442 POBJECT_HANDLE_INFORMATION
443 HandleInformationPtr
)
445 * FUNCTION: Increments the reference count for an object and returns a
446 * pointer to its body
448 * Handle = Handle for the object
449 * DesiredAccess = Desired access to the object
452 * Object (OUT) = Points to the object body on return
453 * HandleInformation (OUT) = Contains information about the handle
458 PHANDLE_REP HandleRep
;
459 POBJECT_HEADER ObjectHeader
;
462 ACCESS_MASK GrantedAccess
;
464 ASSERT_IRQL(PASSIVE_LEVEL
);
466 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
467 "ObjectType %x, AccessMode %d, Object %x)\n",Handle
,DesiredAccess
,
468 ObjectType
,AccessMode
,Object
);
472 * Handle special handle names
474 if (Handle
== NtCurrentProcess() &&
475 (ObjectType
== PsProcessType
|| ObjectType
== NULL
))
477 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
479 ObReferenceObjectByPointer(PsGetCurrentProcess(),
483 *Object
= PsGetCurrentProcess();
484 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
485 return(STATUS_SUCCESS
);
487 else if (Handle
== NtCurrentProcess())
490 return(STATUS_OBJECT_TYPE_MISMATCH
);
492 if (Handle
== NtCurrentThread() &&
493 (ObjectType
== PsThreadType
|| ObjectType
== NULL
))
495 ObReferenceObjectByPointer(PsGetCurrentThread(),
499 *Object
= PsGetCurrentThread();
501 return(STATUS_SUCCESS
);
503 else if (Handle
== NtCurrentThread())
506 return(STATUS_OBJECT_TYPE_MISMATCH
);
509 KeAcquireSpinLock(&PsGetCurrentProcess()->Pcb
.HandleTable
.ListLock
,
511 HandleRep
= ObpGetObjectByHandle(&PsGetCurrentProcess()->Pcb
.HandleTable
,
513 if (HandleRep
== NULL
|| HandleRep
->ObjectBody
== NULL
)
515 KeReleaseSpinLock(&PsGetCurrentProcess()->Pcb
.HandleTable
.ListLock
,
517 return(STATUS_INVALID_HANDLE
);
519 ObjectBody
= HandleRep
->ObjectBody
;
520 ObReferenceObjectByPointer(ObjectBody
,
524 GrantedAccess
= HandleRep
->GrantedAccess
;
525 KeReleaseSpinLock(&PsGetCurrentProcess()->Pcb
.HandleTable
.ListLock
,
528 ObjectHeader
= BODY_TO_HEADER(ObjectBody
);
530 if (ObjectType
!= NULL
&& ObjectType
!= ObjectHeader
->ObjectType
)
533 return(STATUS_OBJECT_TYPE_MISMATCH
);
536 if (ObjectHeader
->ObjectType
== PsProcessType
)
538 DPRINT("Reference from %x\n", ((PULONG
)&Handle
)[-1]);
541 if (!(GrantedAccess
& DesiredAccess
) &&
542 !((~GrantedAccess
) & DesiredAccess
))
545 return(STATUS_ACCESS_DENIED
);
548 *Object
= ObjectBody
;
551 return(STATUS_SUCCESS
);
555 /**********************************************************************
560 * Closes a handle reference to an object.
569 NTSTATUS STDCALL
NtClose(HANDLE Handle
)
572 POBJECT_HEADER Header
;
574 assert_irql(PASSIVE_LEVEL
);
576 DPRINT("NtClose(Handle %x)\n",Handle
);
578 ObjectBody
= ObDeleteHandle(PsGetCurrentProcess(), Handle
);
580 Header
= BODY_TO_HEADER(ObjectBody
);
582 DPRINT("Dereferencing %x\n", ObjectBody
);
583 ObDereferenceObject(ObjectBody
);
585 return STATUS_SUCCESS
;