Sync with trunk r58033.
[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: 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 /* FUNCTIONS *****************************************************************/
19
20 static
21 BOOL
22 CsrIsConsoleHandle(HANDLE Handle)
23 {
24 return ((ULONG_PTR)Handle & 0x10000003) == 0x3;
25 }
26
27 static INT
28 AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change)
29 {
30 Object_t *Object = Entry->Object;
31 if (Entry->Access & GENERIC_READ) Object->AccessRead += Change;
32 if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change;
33 if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change;
34 if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
35 Object->HandleCount += Change;
36 return Object->HandleCount;
37 }
38
39 static VOID
40 Win32CsrCreateHandleEntry(PCSRSS_HANDLE Entry)
41 {
42 Object_t *Object = Entry->Object;
43 EnterCriticalSection(&Object->Console->Lock);
44 AdjustHandleCounts(Entry, +1);
45 LeaveCriticalSection(&Object->Console->Lock);
46 }
47
48 static VOID
49 Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry)
50 {
51 Object_t *Object = Entry->Object;
52 if (Object != NULL)
53 {
54 PCSRSS_CONSOLE Console = Object->Console;
55 EnterCriticalSection(&Console->Lock);
56 /* If the last handle to a screen buffer is closed, delete it */
57 if (AdjustHandleCounts(Entry, -1) == 0
58 && Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
59 {
60 PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER)Object;
61 /* ...unless it's the only buffer left. Windows allows deletion
62 * even of the last buffer, but having to deal with a lack of
63 * any active buffer might be error-prone. */
64 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
65 ConioDeleteScreenBuffer(Buffer);
66 }
67 LeaveCriticalSection(&Console->Lock);
68 Entry->Object = NULL;
69 }
70 }
71
72 NTSTATUS
73 FASTCALL
74 Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData,
75 HANDLE Handle)
76 {
77 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
78 Object_t *Object;
79
80 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
81 if (h >= ProcessData->HandleTableSize
82 || (Object = ProcessData->HandleTable[h].Object) == NULL)
83 {
84 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
85 return STATUS_INVALID_HANDLE;
86 }
87 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]);
88 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
89 return STATUS_SUCCESS;
90 }
91
92 NTSTATUS
93 FASTCALL
94 Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData,
95 HANDLE Handle,
96 Object_t **Object,
97 DWORD Access,
98 LONG Type)
99 {
100 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
101
102 DPRINT("Win32CsrLockObject, Object: %x, %x, %x\n",
103 Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
104
105 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
106 if (!CsrIsConsoleHandle(Handle) || h >= ProcessData->HandleTableSize
107 || (*Object = ProcessData->HandleTable[h].Object) == NULL
108 || ~ProcessData->HandleTable[h].Access & Access
109 || (Type != 0 && (*Object)->Type != Type))
110 {
111 DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle);
112 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
113 return STATUS_INVALID_HANDLE;
114 }
115 _InterlockedIncrement(&(*Object)->Console->ReferenceCount);
116 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
117
118 EnterCriticalSection(&((*Object)->Console->Lock));
119 return STATUS_SUCCESS;
120 }
121
122 VOID
123 FASTCALL
124 Win32CsrUnlockObject(Object_t *Object)
125 {
126 PCSRSS_CONSOLE Console = Object->Console;
127 LeaveCriticalSection(&Console->Lock);
128 /* dec ref count */
129 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
130 ConioDeleteConsole(&Console->Header);
131 }
132
133 NTSTATUS
134 NTAPI
135 ConsoleNewProcess(PCSR_PROCESS SourceProcess,
136 PCSR_PROCESS TargetProcess)
137 {
138 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
139 ULONG i;
140
141 DPRINT1("ConsoleNewProcess inside\n");
142 DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess);
143
144 /* An empty target process is invalid */
145 if (!TargetProcess)
146 return STATUS_INVALID_PARAMETER;
147
148 DPRINT1("ConsoleNewProcess - OK\n");
149
150 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
151
152 /* Initialize the new (target) process */
153 TargetProcessData->Process = TargetProcess;
154 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
155
156 /* Do nothing if the source process is NULL */
157 if (!SourceProcess)
158 return STATUS_SUCCESS;
159
160 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
161
162 // TODO: Check if one of the processes is really a CONSOLE.
163 /*
164 if (!(CreateProcessRequest->CreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
165 {
166 // NewProcess == TargetProcess.
167 NewProcess->ParentConsole = Process->Console;
168 NewProcess->bInheritHandles = CreateProcessRequest->bInheritHandles;
169 }
170 */
171
172 /* Only inherit if the if the flag was set */
173 if (!TargetProcessData->bInheritHandles) return STATUS_SUCCESS;
174
175 if (TargetProcessData->HandleTableSize)
176 {
177 return STATUS_INVALID_PARAMETER;
178 }
179
180 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
181
182 TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
183 HEAP_ZERO_MEMORY,
184 SourceProcessData->HandleTableSize
185 * sizeof(CSRSS_HANDLE));
186 if (TargetProcessData->HandleTable == NULL)
187 {
188 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
189 return STATUS_UNSUCCESSFUL;
190 }
191
192 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
193
194 for (i = 0; i < SourceProcessData->HandleTableSize; i++)
195 {
196 if (SourceProcessData->HandleTable[i].Object != NULL &&
197 SourceProcessData->HandleTable[i].Inheritable)
198 {
199 TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
200 Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
201 }
202 }
203
204 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
205
206 return STATUS_SUCCESS;
207 }
208
209 VOID
210 WINAPI
211 Win32CsrReleaseConsole(PCSR_PROCESS Process)
212 {
213 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
214 PCSRSS_CONSOLE Console;
215 ULONG i;
216
217 /* Close all console handles and detach process from console */
218 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
219
220 for (i = 0; i < ProcessData->HandleTableSize; i++)
221 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
222 ProcessData->HandleTableSize = 0;
223 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
224 ProcessData->HandleTable = NULL;
225
226 Console = ProcessData->Console;
227 if (Console != NULL)
228 {
229 ProcessData->Console = NULL;
230 EnterCriticalSection(&Console->Lock);
231 RemoveEntryList(&ProcessData->ConsoleLink);
232 LeaveCriticalSection(&Console->Lock);
233 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
234 ConioDeleteConsole(&Console->Header);
235 //CloseHandle(ProcessData->ConsoleEvent);
236 //ProcessData->ConsoleEvent = NULL;
237 }
238 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
239 }
240
241 NTSTATUS
242 FASTCALL
243 Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
244 PHANDLE Handle,
245 Object_t *Object,
246 DWORD Access,
247 BOOL Inheritable,
248 DWORD ShareMode)
249 {
250 ULONG i;
251 PCSRSS_HANDLE Block;
252
253 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
254
255 for (i = 0; i < ProcessData->HandleTableSize; i++)
256 {
257 if (ProcessData->HandleTable[i].Object == NULL)
258 {
259 break;
260 }
261 }
262 if (i >= ProcessData->HandleTableSize)
263 {
264 Block = RtlAllocateHeap(ConSrvHeap,
265 HEAP_ZERO_MEMORY,
266 (ProcessData->HandleTableSize + 64) * sizeof(CSRSS_HANDLE));
267 if (Block == NULL)
268 {
269 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
270 return(STATUS_UNSUCCESSFUL);
271 }
272 RtlCopyMemory(Block,
273 ProcessData->HandleTable,
274 ProcessData->HandleTableSize * sizeof(CSRSS_HANDLE));
275 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
276 ProcessData->HandleTable = Block;
277 ProcessData->HandleTableSize += 64;
278 }
279 ProcessData->HandleTable[i].Object = Object;
280 ProcessData->HandleTable[i].Access = Access;
281 ProcessData->HandleTable[i].Inheritable = Inheritable;
282 ProcessData->HandleTable[i].ShareMode = ShareMode;
283 Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]);
284 *Handle = UlongToHandle((i << 2) | 0x3);
285 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
286 return STATUS_SUCCESS;
287 }
288
289 CSR_API(SrvCloseHandle)
290 {
291 PCSRSS_CLOSE_HANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
292
293 return Win32CsrReleaseObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
294 CloseHandleRequest->Handle);
295 }
296
297 CSR_API(SrvVerifyConsoleIoHandle)
298 {
299 NTSTATUS Status = STATUS_SUCCESS;
300 PCSRSS_VERIFY_HANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
301 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
302 ULONG_PTR Index;
303
304 Index = (ULONG_PTR)VerifyHandleRequest->Handle >> 2;
305 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
306 if (Index >= ProcessData->HandleTableSize ||
307 ProcessData->HandleTable[Index].Object == NULL)
308 {
309 DPRINT("CsrVerifyObject failed\n");
310 Status = STATUS_INVALID_HANDLE;
311 }
312 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
313
314 return Status;
315 }
316
317 CSR_API(SrvDuplicateHandle)
318 {
319 ULONG_PTR Index;
320 PCSRSS_HANDLE Entry;
321 DWORD DesiredAccess;
322 PCSRSS_DUPLICATE_HANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
323 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
324
325 Index = (ULONG_PTR)DuplicateHandleRequest->Handle >> 2;
326 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
327 if (Index >= ProcessData->HandleTableSize
328 || (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
329 {
330 DPRINT1("Couldn't dup invalid handle %p\n", DuplicateHandleRequest->Handle);
331 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
332 return STATUS_INVALID_HANDLE;
333 }
334
335 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
336 {
337 DesiredAccess = Entry->Access;
338 }
339 else
340 {
341 DesiredAccess = DuplicateHandleRequest->Access;
342 /* Make sure the source handle has all the desired flags */
343 if (~Entry->Access & DesiredAccess)
344 {
345 DPRINT1("Handle %p only has access %X; requested %X\n",
346 DuplicateHandleRequest->Handle, Entry->Access, DesiredAccess);
347 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
348 return STATUS_INVALID_PARAMETER;
349 }
350 }
351
352 ApiMessage->Status = Win32CsrInsertObject(ProcessData,
353 &DuplicateHandleRequest->Handle,
354 Entry->Object,
355 DesiredAccess,
356 DuplicateHandleRequest->Inheritable,
357 Entry->ShareMode);
358 if (NT_SUCCESS(ApiMessage->Status)
359 && DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
360 {
361 Win32CsrCloseHandleEntry(Entry);
362 }
363
364 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
365 return ApiMessage->Status;
366 }
367
368 CSR_API(CsrGetInputWaitHandle)
369 {
370 PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle;
371
372 GetConsoleInputWaitHandle->InputWaitHandle =
373 ConsoleGetPerProcessData(CsrGetClientThread()->Process)->ConsoleEvent;
374
375 return STATUS_SUCCESS;
376 }
377
378 /* EOF */