Sync to trunk head (r47736)
[reactos.git] / subsystems / win32 / csrss / win32csr / handle.c
1 /* $Id$
2 *
3 * reactos/subsys/csrss/api/handle.c
4 *
5 * CSRSS handle functions
6 *
7 * ReactOS Operating System
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <w32csr.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 static
20 BOOL
21 CsrIsConsoleHandle(HANDLE Handle)
22 {
23 return ((ULONG_PTR)Handle & 0x10000003) == 0x3;
24 }
25
26 static INT
27 AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change)
28 {
29 Object_t *Object = Entry->Object;
30 if (Entry->Access & GENERIC_READ) Object->AccessRead += Change;
31 if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change;
32 if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change;
33 if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
34 Object->HandleCount += Change;
35 return Object->HandleCount;
36 }
37
38 static VOID
39 Win32CsrCreateHandleEntry(
40 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(
50 PCSRSS_HANDLE Entry)
51 {
52 Object_t *Object = Entry->Object;
53 if (Object != NULL)
54 {
55 PCSRSS_CONSOLE Console = Object->Console;
56 EnterCriticalSection(&Console->Lock);
57 /* If the last handle to a screen buffer is closed, delete it */
58 if (AdjustHandleCounts(Entry, -1) == 0
59 && Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
60 {
61 PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER)Object;
62 /* ...unless it's the only buffer left. Windows allows deletion
63 * even of the last buffer, but having to deal with a lack of
64 * any active buffer might be error-prone. */
65 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
66 ConioDeleteScreenBuffer(Buffer);
67 }
68 LeaveCriticalSection(&Console->Lock);
69 Entry->Object = NULL;
70 }
71 }
72
73 NTSTATUS
74 FASTCALL
75 Win32CsrReleaseObject(
76 PCSRSS_PROCESS_DATA ProcessData,
77 HANDLE Handle)
78 {
79 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
80 Object_t *Object;
81
82 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
83 if (h >= ProcessData->HandleTableSize
84 || (Object = ProcessData->HandleTable[h].Object) == NULL)
85 {
86 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
87 return STATUS_INVALID_HANDLE;
88 }
89 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]);
90 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
91 return STATUS_SUCCESS;
92 }
93
94 NTSTATUS
95 FASTCALL
96 Win32CsrLockObject(PCSRSS_PROCESS_DATA ProcessData,
97 HANDLE Handle,
98 Object_t **Object,
99 DWORD Access,
100 LONG Type)
101 {
102 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
103
104 DPRINT("CsrGetObject, Object: %x, %x, %x\n",
105 Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
106
107 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
108 if (!CsrIsConsoleHandle(Handle) || h >= ProcessData->HandleTableSize
109 || (*Object = ProcessData->HandleTable[h].Object) == NULL
110 || ~ProcessData->HandleTable[h].Access & Access
111 || (Type != 0 && (*Object)->Type != Type))
112 {
113 DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle);
114 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
115 return STATUS_INVALID_HANDLE;
116 }
117 _InterlockedIncrement(&(*Object)->Console->ReferenceCount);
118 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
119
120 EnterCriticalSection(&((*Object)->Console->Lock));
121 return STATUS_SUCCESS;
122 }
123
124 VOID
125 FASTCALL
126 Win32CsrUnlockObject(Object_t *Object)
127 {
128 PCSRSS_CONSOLE Console = Object->Console;
129 LeaveCriticalSection(&Console->Lock);
130 /* dec ref count */
131 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
132 ConioDeleteConsole(&Console->Header);
133 }
134
135 NTSTATUS
136 WINAPI
137 Win32CsrReleaseConsole(
138 PCSRSS_PROCESS_DATA ProcessData)
139 {
140 PCSRSS_CONSOLE Console;
141 ULONG i;
142
143 /* Close all console handles and detach process from console */
144 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
145
146 for (i = 0; i < ProcessData->HandleTableSize; i++)
147 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
148 ProcessData->HandleTableSize = 0;
149 RtlFreeHeap(Win32CsrApiHeap, 0, ProcessData->HandleTable);
150 ProcessData->HandleTable = NULL;
151
152 Console = ProcessData->Console;
153 if (Console != NULL)
154 {
155 ProcessData->Console = NULL;
156 EnterCriticalSection(&Console->Lock);
157 RemoveEntryList(&ProcessData->ProcessEntry);
158 LeaveCriticalSection(&Console->Lock);
159 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
160 ConioDeleteConsole(&Console->Header);
161 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
162 return STATUS_SUCCESS;
163 }
164 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
165 return STATUS_INVALID_PARAMETER;
166 }
167
168 NTSTATUS
169 FASTCALL
170 Win32CsrInsertObject(
171 PCSRSS_PROCESS_DATA ProcessData,
172 PHANDLE Handle,
173 Object_t *Object,
174 DWORD Access,
175 BOOL Inheritable,
176 DWORD ShareMode)
177 {
178 ULONG i;
179 PCSRSS_HANDLE Block;
180
181 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
182
183 for (i = 0; i < ProcessData->HandleTableSize; i++)
184 {
185 if (ProcessData->HandleTable[i].Object == NULL)
186 {
187 break;
188 }
189 }
190 if (i >= ProcessData->HandleTableSize)
191 {
192 Block = RtlAllocateHeap(Win32CsrApiHeap,
193 HEAP_ZERO_MEMORY,
194 (ProcessData->HandleTableSize + 64) * sizeof(CSRSS_HANDLE));
195 if (Block == NULL)
196 {
197 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
198 return(STATUS_UNSUCCESSFUL);
199 }
200 RtlCopyMemory(Block,
201 ProcessData->HandleTable,
202 ProcessData->HandleTableSize * sizeof(CSRSS_HANDLE));
203 RtlFreeHeap(Win32CsrApiHeap, 0, ProcessData->HandleTable);
204 ProcessData->HandleTable = Block;
205 ProcessData->HandleTableSize += 64;
206 }
207 ProcessData->HandleTable[i].Object = Object;
208 ProcessData->HandleTable[i].Access = Access;
209 ProcessData->HandleTable[i].Inheritable = Inheritable;
210 ProcessData->HandleTable[i].ShareMode = ShareMode;
211 Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]);
212 *Handle = UlongToHandle((i << 2) | 0x3);
213 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
214 return(STATUS_SUCCESS);
215 }
216
217 NTSTATUS
218 WINAPI
219 Win32CsrDuplicateHandleTable(
220 PCSRSS_PROCESS_DATA SourceProcessData,
221 PCSRSS_PROCESS_DATA TargetProcessData)
222 {
223 ULONG i;
224
225 if (TargetProcessData->HandleTableSize)
226 {
227 return STATUS_INVALID_PARAMETER;
228 }
229
230 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
231
232 /* we are called from CreateProcessData, it isn't necessary to lock the target process data */
233
234 TargetProcessData->HandleTable = RtlAllocateHeap(Win32CsrApiHeap,
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 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
244 for (i = 0; i < SourceProcessData->HandleTableSize; i++)
245 {
246 if (SourceProcessData->HandleTable[i].Object != NULL &&
247 SourceProcessData->HandleTable[i].Inheritable)
248 {
249 TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
250 Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
251 }
252 }
253 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
254 return(STATUS_SUCCESS);
255 }
256
257 CSR_API(CsrGetHandle)
258 {
259 NTSTATUS Status = STATUS_SUCCESS;
260
261 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
262 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
263
264 Request->Data.GetInputHandleRequest.Handle = INVALID_HANDLE_VALUE;
265
266 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
267 if (ProcessData->Console)
268 {
269 DWORD DesiredAccess = Request->Data.GetInputHandleRequest.Access;
270 DWORD ShareMode = Request->Data.GetInputHandleRequest.ShareMode;
271
272 PCSRSS_CONSOLE Console = ProcessData->Console;
273 Object_t *Object;
274
275 EnterCriticalSection(&Console->Lock);
276 if (Request->Type == GET_OUTPUT_HANDLE)
277 Object = &Console->ActiveBuffer->Header;
278 else
279 Object = &Console->Header;
280
281 if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) ||
282 ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
283 (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) ||
284 (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0))
285 {
286 DPRINT1("Sharing violation\n");
287 Status = STATUS_SHARING_VIOLATION;
288 }
289 else
290 {
291 Status = Win32CsrInsertObject(ProcessData,
292 &Request->Data.GetInputHandleRequest.Handle,
293 Object,
294 DesiredAccess,
295 Request->Data.GetInputHandleRequest.Inheritable,
296 ShareMode);
297 }
298 LeaveCriticalSection(&Console->Lock);
299 }
300 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
301
302 return Status;
303 }
304
305 CSR_API(CsrCloseHandle)
306 {
307 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
308 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
309
310 return Win32CsrReleaseObject(ProcessData, Request->Data.CloseHandleRequest.Handle);
311 }
312
313 CSR_API(CsrVerifyHandle)
314 {
315 ULONG_PTR Index;
316 NTSTATUS Status = STATUS_SUCCESS;
317
318 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
319 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
320
321 Index = (ULONG_PTR)Request->Data.VerifyHandleRequest.Handle >> 2;
322 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
323 if (Index >= ProcessData->HandleTableSize ||
324 ProcessData->HandleTable[Index].Object == NULL)
325 {
326 DPRINT("CsrVerifyObject failed\n");
327 Status = STATUS_INVALID_HANDLE;
328 }
329 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
330
331 return Status;
332 }
333
334 CSR_API(CsrDuplicateHandle)
335 {
336 ULONG_PTR Index;
337 PCSRSS_HANDLE Entry;
338 DWORD DesiredAccess;
339
340 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
341 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
342
343 Index = (ULONG_PTR)Request->Data.DuplicateHandleRequest.Handle >> 2;
344 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
345 if (Index >= ProcessData->HandleTableSize
346 || (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
347 {
348 DPRINT1("Couldn't dup invalid handle %p\n", Request->Data.DuplicateHandleRequest.Handle);
349 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
350 return STATUS_INVALID_HANDLE;
351 }
352
353 if (Request->Data.DuplicateHandleRequest.Options & DUPLICATE_SAME_ACCESS)
354 {
355 DesiredAccess = Entry->Access;
356 }
357 else
358 {
359 DesiredAccess = Request->Data.DuplicateHandleRequest.Access;
360 /* Make sure the source handle has all the desired flags */
361 if (~Entry->Access & DesiredAccess)
362 {
363 DPRINT1("Handle %p only has access %X; requested %X\n",
364 Request->Data.DuplicateHandleRequest.Handle, Entry->Access, DesiredAccess);
365 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
366 return STATUS_INVALID_PARAMETER;
367 }
368 }
369
370 Request->Status = Win32CsrInsertObject(ProcessData,
371 &Request->Data.DuplicateHandleRequest.Handle,
372 Entry->Object,
373 DesiredAccess,
374 Request->Data.DuplicateHandleRequest.Inheritable,
375 Entry->ShareMode);
376 if (NT_SUCCESS(Request->Status)
377 && Request->Data.DuplicateHandleRequest.Options & DUPLICATE_CLOSE_SOURCE)
378 {
379 Win32CsrCloseHandleEntry(Entry);
380 }
381
382 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
383 return Request->Status;
384 }
385
386 CSR_API(CsrGetInputWaitHandle)
387 {
388 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
389 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
390
391 Request->Data.GetConsoleInputWaitHandle.InputWaitHandle = ProcessData->ConsoleEvent;
392 return STATUS_SUCCESS;
393 }
394
395 /* EOF */