1 /* $Id: handle.c,v 1.11 1999/08/29 06:59:11 ea 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 ****************************************************************/
15 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
18 #include <internal/string.h>
19 #include <internal/ps.h>
22 #include <internal/debug.h>
24 /* TYPES *******************************************************************/
26 #define HANDLE_BLOCK_ENTRIES ((PAGESIZE-sizeof(LIST_ENTRY))/sizeof(HANDLE_REP))
29 * PURPOSE: Defines a page's worth of handles
34 HANDLE_REP handles
[HANDLE_BLOCK_ENTRIES
];
37 /* FUNCTIONS ***************************************************************/
42 ObpGetObjectByHandle(PEPROCESS Process
,
45 * FUNCTION: Get the data structure for a handle
47 * Process = Process to get the handle for
49 * ARGUMENTS: A pointer to the information about the handle on success,
54 unsigned int handle
= ((unsigned int)h
) - 1;
55 unsigned int count
=handle
/HANDLE_BLOCK_ENTRIES
;
56 HANDLE_BLOCK
* blk
= NULL
;
59 DPRINT("ObpGetObjectByHandle(Process %x, h %x)\n",Process
,h
);
61 current
= Process
->Pcb
.HandleTable
.ListHead
.Flink
;
62 DPRINT("current %x\n",current
);
66 current
= current
->Flink
;
67 if (current
== (&(Process
->Pcb
.HandleTable
.ListHead
)))
73 blk
= CONTAINING_RECORD(current
,HANDLE_BLOCK
,entry
);
74 return(&(blk
->handles
[handle
%HANDLE_BLOCK_ENTRIES
]));
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
,
90 * FUNCTION: Copies a handle from one process space to another
92 * SourceProcessHandle = The source process owning the handle. The
93 * source process should have opened
94 * the SourceHandle with PROCESS_DUP_HANDLE
96 * SourceHandle = The handle to the object.
97 * TargetProcessHandle = The destination process owning the handle
98 * TargetHandle (OUT) = Caller should supply storage for the
100 * DesiredAccess = The desired access to the handle.
101 * InheritHandle = Indicates wheter the new handle will be inheritable
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
111 * REMARKS: This function maps to the win32 DuplicateHandle.
114 PEPROCESS SourceProcess
;
115 PEPROCESS TargetProcess
;
116 PHANDLE_REP SourceHandleRep
;
118 ASSERT_IRQL(PASSIVE_LEVEL
);
120 ObReferenceObjectByHandle(SourceProcessHandle
,
124 (PVOID
*)&SourceProcess
,
126 ObReferenceObjectByHandle(TargetProcessHandle
,
130 (PVOID
*)&TargetProcess
,
133 SourceHandleRep
= ObpGetObjectByHandle(SourceProcess
,
136 if (Options
& DUPLICATE_SAME_ACCESS
)
138 DesiredAccess
= SourceHandleRep
->GrantedAccess
;
141 ObCreateHandle(TargetProcess
,
142 SourceHandleRep
->ObjectBody
,
147 if (Options
& DUPLICATE_CLOSE_SOURCE
)
149 ZwClose(*SourceHandle
);
152 ObDereferenceObject(TargetProcess
);
153 ObDereferenceObject(SourceProcess
);
155 return(STATUS_SUCCESS
);
160 ObDeleteHandleTable(PEPROCESS Process
)
162 * FUNCTION: Deletes the handle table associated with a process
165 PLIST_ENTRY current
= NULL
;
167 PHANDLE_TABLE HandleTable
= NULL
;
169 HandleTable
= &Process
->Pcb
.HandleTable
;
170 current
= RemoveHeadList(&HandleTable
->ListHead
);
172 while (current
!=NULL
)
174 HANDLE_BLOCK
* HandleBlock
= CONTAINING_RECORD(current
,
179 * Deference every handle in block
181 for (i
=0;i
<HANDLE_BLOCK_ENTRIES
;i
++)
183 if (HandleBlock
->handles
[i
].ObjectBody
!= NULL
)
185 ObDereferenceObject(HandleBlock
->handles
[i
].ObjectBody
);
189 ExFreePool(HandleBlock
);
191 current
= RemoveHeadList(&HandleTable
->ListHead
);
197 ObCreateHandleTable(PEPROCESS Parent
,
201 * FUNCTION: Creates a handle table for a process
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
208 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
209 Parent
,Inherit
,Process
);
211 InitializeListHead(&(Process
->Pcb
.HandleTable
.ListHead
));
212 KeInitializeSpinLock(&(Process
->Pcb
.HandleTable
.ListLock
));
221 ObDeleteHandle(HANDLE Handle
)
225 DPRINT("ObDeleteHandle(Handle %x)\n",Handle
);
227 Rep
= ObpGetObjectByHandle(PsGetCurrentProcess(),Handle
);
228 Rep
->ObjectBody
=NULL
;
229 DPRINT("Finished ObDeleteHandle()\n");
234 ObCreateHandle(PEPROCESS Process
,
236 ACCESS_MASK GrantedAccess
,
238 PHANDLE HandleReturn
)
240 * FUNCTION: Add a handle referencing an object
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
248 unsigned int handle
=1;
250 HANDLE_BLOCK
* new_blk
= NULL
;
251 PHANDLE_TABLE HandleTable
;
254 DPRINT("ObAddHandle(Process %x, obj %x)\n",Process
,ObjectBody
);
256 HandleTable
= &Process
->Pcb
.HandleTable
;
258 KeAcquireSpinLock(&HandleTable
->ListLock
, &oldlvl
);
259 current
= HandleTable
->ListHead
.Flink
;
262 * Scan through the currently allocated handle blocks looking for a free
265 while (current
!= (&HandleTable
->ListHead
))
267 HANDLE_BLOCK
* blk
= CONTAINING_RECORD(current
,HANDLE_BLOCK
,entry
);
269 DPRINT("Current %x\n",current
);
271 for (i
=0;i
<HANDLE_BLOCK_ENTRIES
;i
++)
273 DPRINT("Considering slot %d containing %x\n",i
,blk
->handles
[i
]);
274 if (blk
->handles
[i
].ObjectBody
==NULL
)
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
);
285 handle
= handle
+ HANDLE_BLOCK_ENTRIES
;
286 current
= current
->Flink
;
290 * Add a new handle block to the end of the list
292 new_blk
= (HANDLE_BLOCK
*)ExAllocatePool(NonPagedPool
,sizeof(HANDLE_BLOCK
));
293 memset(new_blk
,0,sizeof(HANDLE_BLOCK
));
294 InsertTailList(&(Process
->Pcb
.HandleTable
.ListHead
),
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
);
306 ObReferenceObjectByHandle(HANDLE Handle
,
307 ACCESS_MASK DesiredAccess
,
308 POBJECT_TYPE ObjectType
,
309 KPROCESSOR_MODE AccessMode
,
311 POBJECT_HANDLE_INFORMATION
312 HandleInformationPtr
)
314 * FUNCTION: Increments the reference count for an object and returns a
315 * pointer to its body
317 * Handle = Handle for the object
318 * DesiredAccess = Desired access to the object
321 * Object (OUT) = Points to the object body on return
322 * HandleInformation (OUT) = Contains information about the handle
327 PHANDLE_REP HandleRep
;
328 POBJECT_HEADER ObjectHeader
;
330 ASSERT_IRQL(PASSIVE_LEVEL
);
332 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
333 "ObjectType %x, AccessMode %d, Object %x)\n",Handle
,DesiredAccess
,
334 ObjectType
,AccessMode
,Object
);
338 if (Handle
== NtCurrentProcess() &&
339 (ObjectType
== PsProcessType
|| ObjectType
== NULL
))
341 BODY_TO_HEADER(PsGetCurrentProcess())->RefCount
++;
342 *Object
= PsGetCurrentProcess();
343 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
344 return(STATUS_SUCCESS
);
346 else if (Handle
== NtCurrentProcess())
349 return(STATUS_OBJECT_TYPE_MISMATCH
);
351 if (Handle
== NtCurrentThread() &&
352 (ObjectType
== PsThreadType
|| ObjectType
== NULL
))
354 BODY_TO_HEADER(PsGetCurrentThread())->RefCount
++;
355 *Object
= PsGetCurrentThread();
357 return(STATUS_SUCCESS
);
359 else if (Handle
== NtCurrentThread())
362 return(STATUS_OBJECT_TYPE_MISMATCH
);
365 HandleRep
= ObpGetObjectByHandle(PsGetCurrentProcess(),
367 if (HandleRep
== NULL
|| HandleRep
->ObjectBody
== NULL
)
370 return(STATUS_INVALID_HANDLE
);
373 ObjectHeader
= BODY_TO_HEADER(HandleRep
->ObjectBody
);
375 if (ObjectType
!= NULL
&& ObjectType
!= ObjectHeader
->ObjectType
)
378 return(STATUS_OBJECT_TYPE_MISMATCH
);
381 if (!(HandleRep
->GrantedAccess
& DesiredAccess
))
384 return(STATUS_ACCESS_DENIED
);
387 ObjectHeader
->RefCount
++;
389 *Object
= HandleRep
->ObjectBody
;
392 return(STATUS_SUCCESS
);
396 /**********************************************************************
401 * Closes a handle reference to an object.
412 NtClose(HANDLE Handle
)
415 POBJECT_HEADER Header
;
416 PHANDLE_REP HandleRep
;
418 assert_irql(PASSIVE_LEVEL
);
420 DPRINT("NtClose(Handle %x)\n",Handle
);
422 HandleRep
= ObpGetObjectByHandle(
423 PsGetCurrentProcess(),
426 if (HandleRep
== NULL
)
428 return STATUS_INVALID_HANDLE
;
430 ObjectBody
= HandleRep
->ObjectBody
;
432 HandleRep
->ObjectBody
= NULL
;
434 Header
= BODY_TO_HEADER(ObjectBody
);
437 Header
->HandleCount
--;
439 if ( (Header
->ObjectType
!= NULL
)
440 && (Header
->ObjectType
->Close
!= NULL
)
443 Header
->ObjectType
->Close(
451 ObPerformRetentionChecks(Header
);
453 return STATUS_SUCCESS
;