[KERNEL32/CONSRV]
[reactos.git] / win32ss / user / consrv / handle.c
1 /*
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
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "consrv.h"
12 #include "conio.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17
18 /* PRIVATE FUNCTIONS *********************************************************/
19
20 static INT
21 AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change)
22 {
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;
30 }
31
32 static VOID
33 Win32CsrCreateHandleEntry(PCSRSS_HANDLE Entry)
34 {
35 Object_t *Object = Entry->Object;
36 EnterCriticalSection(&Object->Console->Lock);
37 AdjustHandleCounts(Entry, +1);
38 LeaveCriticalSection(&Object->Console->Lock);
39 }
40
41 static VOID
42 Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry)
43 {
44 Object_t *Object = Entry->Object;
45 if (Object != NULL)
46 {
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)
52 {
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);
59 }
60 LeaveCriticalSection(&Console->Lock);
61 Entry->Object = NULL;
62 }
63 }
64
65
66 /* FUNCTIONS *****************************************************************/
67
68 NTSTATUS
69 FASTCALL
70 Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
71 PHANDLE Handle,
72 Object_t *Object,
73 DWORD Access,
74 BOOL Inheritable,
75 DWORD ShareMode)
76 {
77 ULONG i;
78 PCSRSS_HANDLE Block;
79
80 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
81
82 for (i = 0; i < ProcessData->HandleTableSize; i++)
83 {
84 if (ProcessData->HandleTable[i].Object == NULL)
85 {
86 break;
87 }
88 }
89 if (i >= ProcessData->HandleTableSize)
90 {
91 Block = RtlAllocateHeap(ConSrvHeap,
92 HEAP_ZERO_MEMORY,
93 (ProcessData->HandleTableSize + 64) * sizeof(CSRSS_HANDLE));
94 if (Block == NULL)
95 {
96 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
97 return(STATUS_UNSUCCESSFUL);
98 }
99 RtlCopyMemory(Block,
100 ProcessData->HandleTable,
101 ProcessData->HandleTableSize * sizeof(CSRSS_HANDLE));
102 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
103 ProcessData->HandleTable = Block;
104 ProcessData->HandleTableSize += 64;
105 }
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;
114 }
115
116 NTSTATUS
117 FASTCALL
118 Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData,
119 HANDLE Handle)
120 {
121 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
122 Object_t *Object;
123
124 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
125
126 if (h >= ProcessData->HandleTableSize ||
127 (Object = ProcessData->HandleTable[h].Object) == NULL)
128 {
129 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
130 return STATUS_INVALID_HANDLE;
131 }
132 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]);
133
134 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
135
136 return STATUS_SUCCESS;
137 }
138
139 NTSTATUS
140 FASTCALL
141 Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData,
142 HANDLE Handle,
143 Object_t **Object,
144 DWORD Access,
145 LONG Type)
146 {
147 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
148
149 DPRINT("Win32CsrLockObject, Object: %x, %x, %x\n",
150 Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
151
152 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
153
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) )
159 {
160 DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle);
161 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
162 return STATUS_INVALID_HANDLE;
163 }
164
165 _InterlockedIncrement(&(*Object)->Console->ReferenceCount);
166 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
167
168 EnterCriticalSection(&((*Object)->Console->Lock));
169 return STATUS_SUCCESS;
170 }
171
172 VOID
173 FASTCALL
174 Win32CsrUnlockObject(Object_t *Object)
175 {
176 PCSRSS_CONSOLE Console = Object->Console;
177 LeaveCriticalSection(&Console->Lock);
178 /* dec ref count */
179 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
180 ConioDeleteConsole(&Console->Header);
181 }
182
183
184
185 NTSTATUS
186 NTAPI
187 ConsoleNewProcess(PCSR_PROCESS SourceProcess,
188 PCSR_PROCESS TargetProcess)
189 {
190 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
191 ULONG i;
192
193 DPRINT1("ConsoleNewProcess inside\n");
194 DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess);
195
196 /* An empty target process is invalid */
197 if (!TargetProcess)
198 return STATUS_INVALID_PARAMETER;
199
200 DPRINT1("ConsoleNewProcess - OK\n");
201
202 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
203
204 /* Initialize the new (target) process */
205 TargetProcessData->Process = TargetProcess;
206 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
207
208 /* Do nothing if the source process is NULL */
209 if (!SourceProcess)
210 return STATUS_SUCCESS;
211
212 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
213
214 // TODO: Check if one of the processes is really a CONSOLE.
215 /*
216 if (!(CreateProcessRequest->CreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
217 {
218 // NewProcess == TargetProcess.
219 NewProcess->ParentConsole = Process->Console;
220 NewProcess->bInheritHandles = CreateProcessRequest->bInheritHandles;
221 }
222 */
223
224 /* Only inherit if the if the flag was set */
225 if (!TargetProcessData->bInheritHandles) return STATUS_SUCCESS;
226
227 if (TargetProcessData->HandleTableSize)
228 {
229 return STATUS_INVALID_PARAMETER;
230 }
231
232 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
233
234 TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
235 HEAP_ZERO_MEMORY,
236 SourceProcessData->HandleTableSize
237 * sizeof(CSRSS_HANDLE));
238 if (TargetProcessData->HandleTable == NULL)
239 {
240 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
241 return STATUS_UNSUCCESSFUL;
242 }
243
244 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
245
246 for (i = 0; i < SourceProcessData->HandleTableSize; i++)
247 {
248 if (SourceProcessData->HandleTable[i].Object != NULL &&
249 SourceProcessData->HandleTable[i].Inheritable)
250 {
251 TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
252 Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
253 }
254 }
255
256 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
257
258 return STATUS_SUCCESS;
259 }
260
261 VOID
262 WINAPI
263 Win32CsrReleaseConsole(PCSR_PROCESS Process)
264 {
265 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
266 PCSRSS_CONSOLE Console;
267 ULONG i;
268
269 /* Close all console handles and detach process from console */
270 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
271
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;
277
278 Console = ProcessData->Console;
279 if (Console != NULL)
280 {
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;
289 }
290 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
291 }
292
293 CSR_API(SrvCloseHandle)
294 {
295 PCSRSS_CLOSE_HANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
296
297 return Win32CsrReleaseObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
298 CloseHandleRequest->Handle);
299 }
300
301 CSR_API(SrvVerifyConsoleIoHandle)
302 {
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;
308
309 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
310
311 if (!IsConsoleHandle(Handle) ||
312 Index >= ProcessData->HandleTableSize ||
313 ProcessData->HandleTable[Index].Object == NULL)
314 {
315 DPRINT("CsrVerifyObject failed\n");
316 Status = STATUS_INVALID_HANDLE;
317 }
318
319 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
320
321 return Status;
322 }
323
324 CSR_API(SrvDuplicateHandle)
325 {
326 PCSRSS_HANDLE Entry;
327 DWORD DesiredAccess;
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;
332
333 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
334
335 if ( /** !IsConsoleHandle(Handle) || **/
336 Index >= ProcessData->HandleTableSize ||
337 (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
338 {
339 DPRINT1("Couldn't duplicate invalid handle %p\n", Handle);
340 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
341 return STATUS_INVALID_HANDLE;
342 }
343
344 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
345 {
346 DesiredAccess = Entry->Access;
347 }
348 else
349 {
350 DesiredAccess = DuplicateHandleRequest->Access;
351 /* Make sure the source handle has all the desired flags */
352 if (~Entry->Access & DesiredAccess)
353 {
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;
358 }
359 }
360
361 ApiMessage->Status = Win32CsrInsertObject(ProcessData,
362 &DuplicateHandleRequest->Handle, // Use the new handle value!
363 Entry->Object,
364 DesiredAccess,
365 DuplicateHandleRequest->Inheritable,
366 Entry->ShareMode);
367 if (NT_SUCCESS(ApiMessage->Status) &&
368 DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
369 {
370 Win32CsrCloseHandleEntry(Entry);
371 }
372
373 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
374 return ApiMessage->Status;
375 }
376
377 CSR_API(CsrGetInputWaitHandle)
378 {
379 PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle;
380
381 GetConsoleInputWaitHandle->InputWaitHandle =
382 ConsoleGetPerProcessData(CsrGetClientThread()->Process)->ConsoleEvent;
383
384 return STATUS_SUCCESS;
385 }
386
387 /* EOF */