2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/handle.c
5 * PURPOSE: Console IO Handle functions
9 /* INCLUDES ******************************************************************/
18 /* PRIVATE FUNCTIONS *********************************************************/
21 AdjustHandleCounts(PCSRSS_HANDLE Entry
, INT Change
)
23 Object_t
*Object
= Entry
->Object
;
24 if (Entry
->Access
& GENERIC_READ
) Object
->AccessRead
+= Change
;
25 if (Entry
->Access
& GENERIC_WRITE
) Object
->AccessWrite
+= Change
;
26 if (!(Entry
->ShareMode
& FILE_SHARE_READ
)) Object
->ExclusiveRead
+= Change
;
27 if (!(Entry
->ShareMode
& FILE_SHARE_WRITE
)) Object
->ExclusiveWrite
+= Change
;
28 Object
->HandleCount
+= Change
;
29 return Object
->HandleCount
;
33 Win32CsrCreateHandleEntry(PCSRSS_HANDLE Entry
)
35 Object_t
*Object
= Entry
->Object
;
36 EnterCriticalSection(&Object
->Console
->Lock
);
37 AdjustHandleCounts(Entry
, +1);
38 LeaveCriticalSection(&Object
->Console
->Lock
);
42 Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry
)
44 Object_t
*Object
= Entry
->Object
;
47 PCSRSS_CONSOLE Console
= Object
->Console
;
48 EnterCriticalSection(&Console
->Lock
);
49 /* If the last handle to a screen buffer is closed, delete it */
50 if (AdjustHandleCounts(Entry
, -1) == 0
51 && Object
->Type
== CONIO_SCREEN_BUFFER_MAGIC
)
53 PCSRSS_SCREEN_BUFFER Buffer
= (PCSRSS_SCREEN_BUFFER
)Object
;
54 /* ...unless it's the only buffer left. Windows allows deletion
55 * even of the last buffer, but having to deal with a lack of
56 * any active buffer might be error-prone. */
57 if (Buffer
->ListEntry
.Flink
!= Buffer
->ListEntry
.Blink
)
58 ConioDeleteScreenBuffer(Buffer
);
60 LeaveCriticalSection(&Console
->Lock
);
66 /* FUNCTIONS *****************************************************************/
70 Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData
,
80 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
82 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
84 if (ProcessData
->HandleTable
[i
].Object
== NULL
)
89 if (i
>= ProcessData
->HandleTableSize
)
91 Block
= RtlAllocateHeap(ConSrvHeap
,
93 (ProcessData
->HandleTableSize
+ 64) * sizeof(CSRSS_HANDLE
));
96 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
97 return(STATUS_UNSUCCESSFUL
);
100 ProcessData
->HandleTable
,
101 ProcessData
->HandleTableSize
* sizeof(CSRSS_HANDLE
));
102 RtlFreeHeap(ConSrvHeap
, 0, ProcessData
->HandleTable
);
103 ProcessData
->HandleTable
= Block
;
104 ProcessData
->HandleTableSize
+= 64;
106 ProcessData
->HandleTable
[i
].Object
= Object
;
107 ProcessData
->HandleTable
[i
].Access
= Access
;
108 ProcessData
->HandleTable
[i
].Inheritable
= Inheritable
;
109 ProcessData
->HandleTable
[i
].ShareMode
= ShareMode
;
110 Win32CsrCreateHandleEntry(&ProcessData
->HandleTable
[i
]);
111 *Handle
= UlongToHandle((i
<< 2) | 0x3);
112 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
113 return STATUS_SUCCESS
;
118 Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData
,
121 ULONG_PTR h
= (ULONG_PTR
)Handle
>> 2;
124 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
126 if (h
>= ProcessData
->HandleTableSize
||
127 (Object
= ProcessData
->HandleTable
[h
].Object
) == NULL
)
129 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
130 return STATUS_INVALID_HANDLE
;
132 Win32CsrCloseHandleEntry(&ProcessData
->HandleTable
[h
]);
134 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
136 return STATUS_SUCCESS
;
141 Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData
,
147 ULONG_PTR h
= (ULONG_PTR
)Handle
>> 2;
149 DPRINT("Win32CsrLockObject, Object: %x, %x, %x\n",
150 Object
, Handle
, ProcessData
? ProcessData
->HandleTableSize
: 0);
152 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
154 if ( !IsConsoleHandle(Handle
) ||
155 h
>= ProcessData
->HandleTableSize
||
156 (*Object
= ProcessData
->HandleTable
[h
].Object
) == NULL
||
157 ~ProcessData
->HandleTable
[h
].Access
& Access
||
158 (Type
!= 0 && (*Object
)->Type
!= Type
) )
160 DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle
);
161 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
162 return STATUS_INVALID_HANDLE
;
165 _InterlockedIncrement(&(*Object
)->Console
->ReferenceCount
);
166 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
168 EnterCriticalSection(&((*Object
)->Console
->Lock
));
169 return STATUS_SUCCESS
;
174 Win32CsrUnlockObject(Object_t
*Object
)
176 PCSRSS_CONSOLE Console
= Object
->Console
;
177 LeaveCriticalSection(&Console
->Lock
);
179 if (_InterlockedDecrement(&Console
->ReferenceCount
) == 0)
180 ConioDeleteConsole(&Console
->Header
);
187 ConsoleNewProcess(PCSR_PROCESS SourceProcess
,
188 PCSR_PROCESS TargetProcess
)
190 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
193 DPRINT1("ConsoleNewProcess inside\n");
194 DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess
, TargetProcess
);
196 /* An empty target process is invalid */
198 return STATUS_INVALID_PARAMETER
;
200 DPRINT1("ConsoleNewProcess - OK\n");
202 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
204 /* Initialize the new (target) process */
205 TargetProcessData
->Process
= TargetProcess
;
206 RtlInitializeCriticalSection(&TargetProcessData
->HandleTableLock
);
208 /* Do nothing if the source process is NULL */
210 return STATUS_SUCCESS
;
212 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
214 // TODO: Check if one of the processes is really a CONSOLE.
216 if (!(CreateProcessRequest->CreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
218 // NewProcess == TargetProcess.
219 NewProcess->ParentConsole = Process->Console;
220 NewProcess->bInheritHandles = CreateProcessRequest->bInheritHandles;
224 /* Only inherit if the if the flag was set */
225 if (!TargetProcessData
->bInheritHandles
) return STATUS_SUCCESS
;
227 if (TargetProcessData
->HandleTableSize
)
229 return STATUS_INVALID_PARAMETER
;
232 RtlEnterCriticalSection(&SourceProcessData
->HandleTableLock
);
234 TargetProcessData
->HandleTable
= RtlAllocateHeap(ConSrvHeap
,
236 SourceProcessData
->HandleTableSize
237 * sizeof(CSRSS_HANDLE
));
238 if (TargetProcessData
->HandleTable
== NULL
)
240 RtlLeaveCriticalSection(&SourceProcessData
->HandleTableLock
);
241 return STATUS_UNSUCCESSFUL
;
244 TargetProcessData
->HandleTableSize
= SourceProcessData
->HandleTableSize
;
246 for (i
= 0; i
< SourceProcessData
->HandleTableSize
; i
++)
248 if (SourceProcessData
->HandleTable
[i
].Object
!= NULL
&&
249 SourceProcessData
->HandleTable
[i
].Inheritable
)
251 TargetProcessData
->HandleTable
[i
] = SourceProcessData
->HandleTable
[i
];
252 Win32CsrCreateHandleEntry(&TargetProcessData
->HandleTable
[i
]);
256 RtlLeaveCriticalSection(&SourceProcessData
->HandleTableLock
);
258 return STATUS_SUCCESS
;
263 Win32CsrReleaseConsole(PCSR_PROCESS Process
)
265 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(Process
);
266 PCSRSS_CONSOLE Console
;
269 /* Close all console handles and detach process from console */
270 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
272 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
273 Win32CsrCloseHandleEntry(&ProcessData
->HandleTable
[i
]);
274 ProcessData
->HandleTableSize
= 0;
275 RtlFreeHeap(ConSrvHeap
, 0, ProcessData
->HandleTable
);
276 ProcessData
->HandleTable
= NULL
;
278 Console
= ProcessData
->Console
;
281 ProcessData
->Console
= NULL
;
282 EnterCriticalSection(&Console
->Lock
);
283 RemoveEntryList(&ProcessData
->ConsoleLink
);
284 LeaveCriticalSection(&Console
->Lock
);
285 if (_InterlockedDecrement(&Console
->ReferenceCount
) == 0)
286 ConioDeleteConsole(&Console
->Header
);
287 //CloseHandle(ProcessData->ConsoleEvent);
288 //ProcessData->ConsoleEvent = NULL;
290 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
293 CSR_API(SrvCloseHandle
)
295 PCSRSS_CLOSE_HANDLE CloseHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CloseHandleRequest
;
297 return Win32CsrReleaseObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
298 CloseHandleRequest
->Handle
);
301 CSR_API(SrvVerifyConsoleIoHandle
)
303 NTSTATUS Status
= STATUS_SUCCESS
;
304 PCSRSS_VERIFY_HANDLE VerifyHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.VerifyHandleRequest
;
305 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
306 HANDLE Handle
= VerifyHandleRequest
->Handle
;
307 ULONG_PTR Index
= (ULONG_PTR
)Handle
>> 2;
309 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
311 if (!IsConsoleHandle(Handle
) ||
312 Index
>= ProcessData
->HandleTableSize
||
313 ProcessData
->HandleTable
[Index
].Object
== NULL
)
315 DPRINT("CsrVerifyObject failed\n");
316 Status
= STATUS_INVALID_HANDLE
;
319 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
324 CSR_API(SrvDuplicateHandle
)
328 PCSRSS_DUPLICATE_HANDLE DuplicateHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.DuplicateHandleRequest
;
329 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
330 HANDLE Handle
= DuplicateHandleRequest
->Handle
;
331 ULONG_PTR Index
= (ULONG_PTR
)Handle
>> 2;
333 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
335 if ( /** !IsConsoleHandle(Handle) || **/
336 Index
>= ProcessData
->HandleTableSize
||
337 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
339 DPRINT1("Couldn't duplicate invalid handle %p\n", Handle
);
340 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
341 return STATUS_INVALID_HANDLE
;
344 if (DuplicateHandleRequest
->Options
& DUPLICATE_SAME_ACCESS
)
346 DesiredAccess
= Entry
->Access
;
350 DesiredAccess
= DuplicateHandleRequest
->Access
;
351 /* Make sure the source handle has all the desired flags */
352 if (~Entry
->Access
& DesiredAccess
)
354 DPRINT1("Handle %p only has access %X; requested %X\n",
355 Handle
, Entry
->Access
, DesiredAccess
);
356 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
357 return STATUS_INVALID_PARAMETER
;
361 ApiMessage
->Status
= Win32CsrInsertObject(ProcessData
,
362 &DuplicateHandleRequest
->Handle
, // Use the new handle value!
365 DuplicateHandleRequest
->Inheritable
,
367 if (NT_SUCCESS(ApiMessage
->Status
) &&
368 DuplicateHandleRequest
->Options
& DUPLICATE_CLOSE_SOURCE
)
370 Win32CsrCloseHandleEntry(Entry
);
373 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
374 return ApiMessage
->Status
;
377 CSR_API(CsrGetInputWaitHandle
)
379 PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetConsoleInputWaitHandle
;
381 GetConsoleInputWaitHandle
->InputWaitHandle
=
382 ConsoleGetPerProcessData(CsrGetClientThread()->Process
)->ConsoleEvent
;
384 return STATUS_SUCCESS
;