[CONSRV]
[reactos.git] / reactos / win32ss / user / winsrv / consrv_new / handle.c
1 /*
2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/handle.c
5 * PURPOSE: Console I/O Handles functions
6 * PROGRAMMERS: David Welch
7 * Jeffrey Morlan
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include "consrv.h"
14 #include "include/conio.h"
15 #include "include/conio2.h"
16 #include "handle.h"
17 #include "include/console.h"
18 #include "console.h"
19 #include "conoutput.h"
20
21 #define NDEBUG
22 #include <debug.h>
23
24
25 /* GLOBALS ********************************************************************/
26
27 typedef struct _CONSOLE_IO_HANDLE
28 {
29 PCONSOLE_IO_OBJECT Object; /* The object on which the handle points to */
30 DWORD Access;
31 BOOL Inheritable;
32 DWORD ShareMode;
33 } CONSOLE_IO_HANDLE, *PCONSOLE_IO_HANDLE;
34
35
36 /* PRIVATE FUNCTIONS **********************************************************/
37
38 static INT
39 AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry, INT Change)
40 {
41 PCONSOLE_IO_OBJECT Object = Entry->Object;
42
43 DPRINT("AdjustHandleCounts(0x%p, %d), Object = 0x%p\n", Entry, Change, Object);
44 DPRINT("\tAdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry, Change, Object, Object->HandleCount, Object->Type);
45
46 if (Entry->Access & GENERIC_READ) Object->AccessRead += Change;
47 if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change;
48 if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change;
49 if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
50
51 Object->HandleCount += Change;
52
53 return Object->HandleCount;
54 }
55
56 static VOID
57 ConSrvCreateHandleEntry(PCONSOLE_IO_HANDLE Entry)
58 {
59 /// LOCK /// PCONSOLE_IO_OBJECT Object = Entry->Object;
60 /// LOCK /// EnterCriticalSection(&Object->Console->Lock);
61 AdjustHandleCounts(Entry, +1);
62 /// LOCK /// LeaveCriticalSection(&Object->Console->Lock);
63 }
64
65 static VOID
66 ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry)
67 {
68 PCONSOLE_IO_OBJECT Object = Entry->Object;
69 if (Object != NULL)
70 {
71 /// LOCK /// PCONSOLE Console = Object->Console;
72 /// LOCK /// EnterCriticalSection(&Console->Lock);
73
74 /*
75 * If this is a input handle, notify and dereference
76 * all the waits related to this handle.
77 */
78 if (Object->Type == INPUT_BUFFER)
79 {
80 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
81
82 /*
83 * Wake up all the writing waiters related to this handle for this
84 * input buffer, if any, then dereference them and purge them all
85 * from the list.
86 * To select them amongst all the waiters for this input buffer,
87 * pass the handle pointer to the waiters, then they will check
88 * whether or not they are related to this handle and if so, they
89 * return.
90 */
91 CsrNotifyWait(&InputBuffer->ReadWaitQueue,
92 WaitAll,
93 NULL,
94 (PVOID)Entry);
95 if (!IsListEmpty(&InputBuffer->ReadWaitQueue))
96 {
97 CsrDereferenceWait(&InputBuffer->ReadWaitQueue);
98 }
99 }
100
101 /* If the last handle to a screen buffer is closed, delete it... */
102 if (AdjustHandleCounts(Entry, -1) == 0)
103 {
104 if (Object->Type == TEXTMODE_BUFFER || Object->Type == GRAPHICS_BUFFER)
105 {
106 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
107 /* ...unless it's the only buffer left. Windows allows deletion
108 * even of the last buffer, but having to deal with a lack of
109 * any active buffer might be error-prone. */
110 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
111 ConioDeleteScreenBuffer(Buffer);
112 }
113 else if (Object->Type == INPUT_BUFFER)
114 {
115 DPRINT("Closing the input buffer\n");
116 }
117 else
118 {
119 DPRINT1("Invalid object type %d\n", Object->Type);
120 }
121 }
122
123 /// LOCK /// LeaveCriticalSection(&Console->Lock);
124
125 /* Invalidate (zero-out) this handle entry */
126 // Entry->Object = NULL;
127 // RtlZeroMemory(Entry, sizeof(*Entry));
128 }
129 RtlZeroMemory(Entry, sizeof(*Entry)); // Be sure the whole entry is invalidated.
130 }
131
132
133 /* Forward declaration, used in ConSrvInitHandlesTable */
134 static VOID ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData);
135
136 static NTSTATUS
137 ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData,
138 IN PCONSOLE Console,
139 OUT PHANDLE pInputHandle,
140 OUT PHANDLE pOutputHandle,
141 OUT PHANDLE pErrorHandle)
142 {
143 NTSTATUS Status;
144 HANDLE InputHandle = INVALID_HANDLE_VALUE,
145 OutputHandle = INVALID_HANDLE_VALUE,
146 ErrorHandle = INVALID_HANDLE_VALUE;
147
148 /*
149 * Initialize the handles table. Use temporary variables to store
150 * the handles values in such a way that, if we fail, we don't
151 * return to the caller invalid handle values.
152 *
153 * Insert the IO handles.
154 */
155
156 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
157
158 /* Insert the Input handle */
159 Status = ConSrvInsertObject(ProcessData,
160 &InputHandle,
161 &Console->InputBuffer.Header,
162 GENERIC_READ | GENERIC_WRITE,
163 TRUE,
164 FILE_SHARE_READ | FILE_SHARE_WRITE);
165 if (!NT_SUCCESS(Status))
166 {
167 DPRINT1("Failed to insert the input handle\n");
168 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
169 ConSrvFreeHandlesTable(ProcessData);
170 return Status;
171 }
172
173 /* Insert the Output handle */
174 Status = ConSrvInsertObject(ProcessData,
175 &OutputHandle,
176 &Console->ActiveBuffer->Header,
177 GENERIC_READ | GENERIC_WRITE,
178 TRUE,
179 FILE_SHARE_READ | FILE_SHARE_WRITE);
180 if (!NT_SUCCESS(Status))
181 {
182 DPRINT1("Failed to insert the output handle\n");
183 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
184 ConSrvFreeHandlesTable(ProcessData);
185 return Status;
186 }
187
188 /* Insert the Error handle */
189 Status = ConSrvInsertObject(ProcessData,
190 &ErrorHandle,
191 &Console->ActiveBuffer->Header,
192 GENERIC_READ | GENERIC_WRITE,
193 TRUE,
194 FILE_SHARE_READ | FILE_SHARE_WRITE);
195 if (!NT_SUCCESS(Status))
196 {
197 DPRINT1("Failed to insert the error handle\n");
198 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
199 ConSrvFreeHandlesTable(ProcessData);
200 return Status;
201 }
202
203 /* Return the newly created handles */
204 *pInputHandle = InputHandle;
205 *pOutputHandle = OutputHandle;
206 *pErrorHandle = ErrorHandle;
207
208 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
209 return STATUS_SUCCESS;
210 }
211
212 NTSTATUS
213 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
214 IN PCONSOLE_PROCESS_DATA TargetProcessData)
215 {
216 NTSTATUS Status = STATUS_SUCCESS;
217 ULONG i, j;
218
219 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
220
221 /* Inherit a handles table only if there is no already */
222 if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */)
223 {
224 Status = STATUS_UNSUCCESSFUL;
225 goto Quit;
226 }
227
228 /* Allocate a new handle table for the child process */
229 TargetProcessData->HandleTable = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
230 SourceProcessData->HandleTableSize
231 * sizeof(CONSOLE_IO_HANDLE));
232 if (TargetProcessData->HandleTable == NULL)
233 {
234 Status = STATUS_NO_MEMORY;
235 goto Quit;
236 }
237
238 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
239
240 /*
241 * Parse the parent process' handles table and, for each handle,
242 * do a copy of it and reference it, if the handle is inheritable.
243 */
244 for (i = 0, j = 0; i < SourceProcessData->HandleTableSize; i++)
245 {
246 if (SourceProcessData->HandleTable[i].Object != NULL &&
247 SourceProcessData->HandleTable[i].Inheritable)
248 {
249 /*
250 * Copy the handle data and increment the reference count of the
251 * pointed object (via the call to ConSrvCreateHandleEntry).
252 */
253 TargetProcessData->HandleTable[j] = SourceProcessData->HandleTable[i];
254 ConSrvCreateHandleEntry(&TargetProcessData->HandleTable[j]);
255 ++j;
256 }
257 }
258
259 Quit:
260 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
261 return Status;
262 }
263
264 static VOID
265 ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
266 {
267 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
268
269 if (ProcessData->HandleTable != NULL)
270 {
271 ULONG i;
272
273 /*
274 * ProcessData->ConsoleHandle is NULL (and the assertion fails) when
275 * ConSrvFreeHandlesTable is called in ConSrvConnect during the
276 * allocation of a new console.
277 */
278 // ASSERT(ProcessData->ConsoleHandle);
279 if (ProcessData->ConsoleHandle != NULL)
280 {
281 /* Close all the console handles */
282 for (i = 0; i < ProcessData->HandleTableSize; i++)
283 {
284 ConSrvCloseHandleEntry(&ProcessData->HandleTable[i]);
285 }
286 }
287 /* Free the handles table memory */
288 ConsoleFreeHeap(ProcessData->HandleTable);
289 ProcessData->HandleTable = NULL;
290 }
291
292 ProcessData->HandleTableSize = 0;
293
294 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
295 }
296
297 VOID
298 FASTCALL
299 ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object,
300 IN CONSOLE_IO_OBJECT_TYPE Type,
301 IN PCONSOLE Console)
302 {
303 ASSERT(Object);
304 // if (!Object) return;
305
306 Object->Type = Type;
307 Object->Console = Console;
308 Object->AccessRead = Object->AccessWrite = 0;
309 Object->ExclusiveRead = Object->ExclusiveWrite = 0;
310 Object->HandleCount = 0;
311 }
312
313 NTSTATUS
314 FASTCALL
315 ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
316 PHANDLE Handle,
317 PCONSOLE_IO_OBJECT Object,
318 DWORD Access,
319 BOOL Inheritable,
320 DWORD ShareMode)
321 {
322 #define IO_HANDLES_INCREMENT 2 * 3
323
324 ULONG i = 0;
325 PCONSOLE_IO_HANDLE Block;
326
327 // NOTE: Commented out because calling code always lock HandleTableLock before.
328 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
329
330 ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
331 (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
332
333 if (ProcessData->HandleTable)
334 {
335 for (i = 0; i < ProcessData->HandleTableSize; i++)
336 {
337 if (ProcessData->HandleTable[i].Object == NULL)
338 break;
339 }
340 }
341
342 if (i >= ProcessData->HandleTableSize)
343 {
344 /* Allocate a new handles table */
345 Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
346 (ProcessData->HandleTableSize +
347 IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE));
348 if (Block == NULL)
349 {
350 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
351 return STATUS_UNSUCCESSFUL;
352 }
353
354 /* If we previously had a handles table, free it and use the new one */
355 if (ProcessData->HandleTable)
356 {
357 /* Copy the handles from the old table to the new one */
358 RtlCopyMemory(Block,
359 ProcessData->HandleTable,
360 ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE));
361 ConsoleFreeHeap(ProcessData->HandleTable);
362 }
363 ProcessData->HandleTable = Block;
364 ProcessData->HandleTableSize += IO_HANDLES_INCREMENT;
365 }
366
367 ProcessData->HandleTable[i].Object = Object;
368 ProcessData->HandleTable[i].Access = Access;
369 ProcessData->HandleTable[i].Inheritable = Inheritable;
370 ProcessData->HandleTable[i].ShareMode = ShareMode;
371 ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]);
372 *Handle = ULongToHandle((i << 2) | 0x3);
373
374 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
375
376 return STATUS_SUCCESS;
377 }
378
379 NTSTATUS
380 FASTCALL
381 ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData,
382 HANDLE Handle)
383 {
384 ULONG Index = HandleToULong(Handle) >> 2;
385 PCONSOLE_IO_OBJECT Object;
386
387 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
388
389 ASSERT(ProcessData->HandleTable);
390
391 if (Index >= ProcessData->HandleTableSize ||
392 (Object = ProcessData->HandleTable[Index].Object) == NULL)
393 {
394 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
395 return STATUS_INVALID_HANDLE;
396 }
397
398 ASSERT(ProcessData->ConsoleHandle);
399 ConSrvCloseHandleEntry(&ProcessData->HandleTable[Index]);
400
401 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
402 return STATUS_SUCCESS;
403 }
404
405 NTSTATUS
406 FASTCALL
407 ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
408 HANDLE Handle,
409 PCONSOLE_IO_OBJECT* Object,
410 PVOID* Entry OPTIONAL,
411 DWORD Access,
412 BOOL LockConsole,
413 CONSOLE_IO_OBJECT_TYPE Type)
414 {
415 // NTSTATUS Status;
416 ULONG Index = HandleToULong(Handle) >> 2;
417 PCONSOLE_IO_HANDLE HandleEntry = NULL;
418 PCONSOLE_IO_OBJECT ObjectEntry = NULL;
419 // PCONSOLE ObjectConsole;
420
421 ASSERT(Object);
422 if (Entry) *Entry = NULL;
423
424 DPRINT("ConSrvGetObject -- Object: 0x%x, Handle: 0x%x\n", Object, Handle);
425
426 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
427
428 if ( IsConsoleHandle(Handle) &&
429 Index < ProcessData->HandleTableSize )
430 {
431 HandleEntry = &ProcessData->HandleTable[Index];
432 ObjectEntry = HandleEntry->Object;
433 }
434
435 if ( HandleEntry == NULL ||
436 ObjectEntry == NULL ||
437 (HandleEntry->Access & Access) == 0 ||
438 /*(Type != 0 && ObjectEntry->Type != Type)*/
439 (Type != 0 && (ObjectEntry->Type & Type) == 0) )
440 {
441 DPRINT("ConSrvGetObject -- Invalid handle 0x%x of type %lu with access %lu ; retrieved object 0x%x (handle 0x%x) of type %lu with access %lu\n",
442 Handle, Type, Access, ObjectEntry, HandleEntry, (ObjectEntry ? ObjectEntry->Type : 0), (HandleEntry ? HandleEntry->Access : 0));
443
444 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
445 return STATUS_INVALID_HANDLE;
446 }
447
448 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
449
450 // Status = ConDrvGetConsole(&ObjectConsole, ProcessData->ConsoleHandle, LockConsole);
451 // if (NT_SUCCESS(Status))
452 if (ConDrvValidateConsoleUnsafe(ObjectEntry->Console, CONSOLE_RUNNING, LockConsole))
453 {
454 _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
455
456 /* Return the objects to the caller */
457 *Object = ObjectEntry;
458 if (Entry) *Entry = HandleEntry;
459
460 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
461 return STATUS_SUCCESS;
462 }
463 else
464 {
465 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
466 return STATUS_INVALID_HANDLE;
467 }
468 }
469
470 VOID
471 FASTCALL
472 ConSrvReleaseObject(PCONSOLE_IO_OBJECT Object,
473 BOOL IsConsoleLocked)
474 {
475 ConSrvReleaseConsole(Object->Console, IsConsoleLocked);
476 }
477
478 NTSTATUS
479 FASTCALL
480 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
481 PHANDLE pInputHandle,
482 PHANDLE pOutputHandle,
483 PHANDLE pErrorHandle,
484 PCONSOLE_START_INFO ConsoleStartInfo)
485 {
486 NTSTATUS Status = STATUS_SUCCESS;
487 HANDLE ConsoleHandle;
488 PCONSOLE Console;
489
490 /*
491 * We are about to create a new console. However when ConSrvNewProcess
492 * was called, we didn't know that we wanted to create a new console and
493 * therefore, we by default inherited the handles table from our parent
494 * process. It's only now that we notice that in fact we do not need
495 * them, because we've created a new console and thus we must use it.
496 *
497 * Therefore, free the handles table so that we can recreate
498 * a new one later on.
499 */
500 ConSrvFreeHandlesTable(ProcessData);
501
502 /* Initialize a new Console owned by this process */
503 Status = ConSrvInitConsole(&ConsoleHandle,
504 &Console,
505 ConsoleStartInfo,
506 HandleToUlong(ProcessData->Process->ClientId.UniqueProcess));
507 if (!NT_SUCCESS(Status))
508 {
509 DPRINT1("Console initialization failed\n");
510 return Status;
511 }
512
513 /* Assign the new console handle */
514 ProcessData->ConsoleHandle = ConsoleHandle;
515
516 /* Initialize the handles table */
517 Status = ConSrvInitHandlesTable(ProcessData,
518 Console,
519 pInputHandle,
520 pOutputHandle,
521 pErrorHandle);
522 if (!NT_SUCCESS(Status))
523 {
524 DPRINT1("Failed to initialize the handles table\n");
525 ConSrvDeleteConsole(Console);
526 ProcessData->ConsoleHandle = NULL;
527 return Status;
528 }
529
530 /* Duplicate the Input Event */
531 Status = NtDuplicateObject(NtCurrentProcess(),
532 Console->InputBuffer.ActiveEvent,
533 ProcessData->Process->ProcessHandle,
534 &ProcessData->ConsoleEvent,
535 EVENT_ALL_ACCESS, 0, 0);
536 if (!NT_SUCCESS(Status))
537 {
538 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
539 ConSrvFreeHandlesTable(ProcessData);
540 ConSrvDeleteConsole(Console);
541 ProcessData->ConsoleHandle = NULL;
542 return Status;
543 }
544
545 /* Insert the process into the processes list of the console */
546 InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
547
548 /* Add a reference count because the process is tied to the console */
549 _InterlockedIncrement(&Console->ReferenceCount);
550
551 /* Update the internal info of the terminal */
552 ConioRefreshInternalInfo(Console);
553
554 return STATUS_SUCCESS;
555 }
556
557 NTSTATUS
558 FASTCALL
559 ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
560 HANDLE ConsoleHandle,
561 BOOL CreateNewHandlesTable,
562 PHANDLE pInputHandle,
563 PHANDLE pOutputHandle,
564 PHANDLE pErrorHandle)
565 {
566 NTSTATUS Status = STATUS_SUCCESS;
567 PCONSOLE Console;
568
569 /* Validate and lock the console */
570 if (!ConDrvValidateConsole(&Console,
571 ConsoleHandle,
572 CONSOLE_RUNNING, TRUE))
573 {
574 // FIXME: Find another status code
575 return STATUS_UNSUCCESSFUL;
576 }
577
578 /* Inherit the console */
579 ProcessData->ConsoleHandle = ConsoleHandle;
580
581 if (CreateNewHandlesTable)
582 {
583 /*
584 * We are about to create a new console. However when ConSrvNewProcess
585 * was called, we didn't know that we wanted to create a new console and
586 * therefore, we by default inherited the handles table from our parent
587 * process. It's only now that we notice that in fact we do not need
588 * them, because we've created a new console and thus we must use it.
589 *
590 * Therefore, free the handles table so that we can recreate
591 * a new one later on.
592 */
593 ConSrvFreeHandlesTable(ProcessData);
594
595 /* Initialize the handles table */
596 Status = ConSrvInitHandlesTable(ProcessData,
597 Console,
598 pInputHandle,
599 pOutputHandle,
600 pErrorHandle);
601 if (!NT_SUCCESS(Status))
602 {
603 DPRINT1("Failed to initialize the handles table\n");
604 ProcessData->ConsoleHandle = NULL;
605 goto Quit;
606 }
607 }
608
609 /* Duplicate the Input Event */
610 Status = NtDuplicateObject(NtCurrentProcess(),
611 Console->InputBuffer.ActiveEvent,
612 ProcessData->Process->ProcessHandle,
613 &ProcessData->ConsoleEvent,
614 EVENT_ALL_ACCESS, 0, 0);
615 if (!NT_SUCCESS(Status))
616 {
617 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
618 ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table.
619 ProcessData->ConsoleHandle = NULL;
620 goto Quit;
621 }
622
623 /* Insert the process into the processes list of the console */
624 InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
625
626 /* Add a reference count because the process is tied to the console */
627 _InterlockedIncrement(&Console->ReferenceCount);
628
629 /* Update the internal info of the terminal */
630 ConioRefreshInternalInfo(Console);
631
632 Status = STATUS_SUCCESS;
633
634 Quit:
635 /* Unlock the console and return */
636 LeaveCriticalSection(&Console->Lock);
637 return Status;
638 }
639
640 VOID
641 FASTCALL
642 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
643 {
644 PCONSOLE Console;
645
646 DPRINT("ConSrvRemoveConsole\n");
647
648 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
649
650 /* Validate and lock the console */
651 if (ConDrvValidateConsole(&Console,
652 ProcessData->ConsoleHandle,
653 CONSOLE_RUNNING, TRUE))
654 {
655 DPRINT("ConSrvRemoveConsole - Locking OK\n");
656
657 /* Close all console handles and free the handles table */
658 ConSrvFreeHandlesTable(ProcessData);
659
660 /* Detach the process from the console */
661 ProcessData->ConsoleHandle = NULL;
662
663 /* Remove ourselves from the console's list of processes */
664 RemoveEntryList(&ProcessData->ConsoleLink);
665
666 /* Update the internal info of the terminal */
667 ConioRefreshInternalInfo(Console);
668
669 /* Release the console */
670 DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
671 ConDrvReleaseConsole(Console, TRUE);
672 //CloseHandle(ProcessData->ConsoleEvent);
673 //ProcessData->ConsoleEvent = NULL;
674 }
675
676 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
677 }
678
679
680 /* PUBLIC SERVER APIS *********************************************************/
681
682 CSR_API(SrvOpenConsole)
683 {
684 /*
685 * This API opens a handle to either the input buffer or to
686 * a screen-buffer of the console of the current process.
687 */
688
689 NTSTATUS Status;
690 PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
691 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
692 PCONSOLE Console;
693
694 DWORD DesiredAccess = OpenConsoleRequest->Access;
695 DWORD ShareMode = OpenConsoleRequest->ShareMode;
696 PCONSOLE_IO_OBJECT Object;
697
698 OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE;
699
700 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
701 if (!NT_SUCCESS(Status))
702 {
703 DPRINT1("Can't get console\n");
704 return Status;
705 }
706
707 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
708
709 /*
710 * Open a handle to either the active screen buffer or the input buffer.
711 */
712 if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
713 {
714 Object = &Console->ActiveBuffer->Header;
715 }
716 else // HANDLE_INPUT
717 {
718 Object = &Console->InputBuffer.Header;
719 }
720
721 if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) ||
722 ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
723 (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) ||
724 (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0))
725 {
726 DPRINT1("Sharing violation\n");
727 Status = STATUS_SHARING_VIOLATION;
728 }
729 else
730 {
731 Status = ConSrvInsertObject(ProcessData,
732 &OpenConsoleRequest->ConsoleHandle,
733 Object,
734 DesiredAccess,
735 OpenConsoleRequest->Inheritable,
736 ShareMode);
737 }
738
739 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
740
741 ConSrvReleaseConsole(Console, TRUE);
742 return Status;
743 }
744
745 CSR_API(SrvCloseHandle)
746 {
747 NTSTATUS Status;
748 PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
749 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
750 PCONSOLE Console;
751
752 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
753 if (!NT_SUCCESS(Status))
754 {
755 DPRINT1("Can't get console\n");
756 return Status;
757 }
758
759 Status = ConSrvRemoveObject(ProcessData, CloseHandleRequest->ConsoleHandle);
760
761 ConSrvReleaseConsole(Console, TRUE);
762 return Status;
763 }
764
765 CSR_API(SrvVerifyConsoleIoHandle)
766 {
767 NTSTATUS Status;
768 PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
769 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
770 PCONSOLE Console;
771
772 HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle;
773 ULONG Index = HandleToULong(ConsoleHandle) >> 2;
774
775 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
776 if (!NT_SUCCESS(Status))
777 {
778 DPRINT1("Can't get console\n");
779 return Status;
780 }
781
782 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
783
784 if (!IsConsoleHandle(ConsoleHandle) ||
785 Index >= ProcessData->HandleTableSize ||
786 ProcessData->HandleTable[Index].Object == NULL)
787 {
788 DPRINT("SrvVerifyConsoleIoHandle failed\n");
789 Status = STATUS_INVALID_HANDLE;
790 }
791
792 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
793
794 ConSrvReleaseConsole(Console, TRUE);
795 return Status;
796 }
797
798 CSR_API(SrvDuplicateHandle)
799 {
800 NTSTATUS Status;
801 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
802 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
803 PCONSOLE Console;
804
805 HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle;
806 ULONG Index = HandleToULong(ConsoleHandle) >> 2;
807 PCONSOLE_IO_HANDLE Entry;
808 DWORD DesiredAccess;
809
810 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
811 if (!NT_SUCCESS(Status))
812 {
813 DPRINT1("Can't get console\n");
814 return Status;
815 }
816
817 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
818
819 if ( /** !IsConsoleHandle(ConsoleHandle) || **/
820 Index >= ProcessData->HandleTableSize ||
821 (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
822 {
823 DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle);
824 Status = STATUS_INVALID_HANDLE;
825 goto Quit;
826 }
827
828 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
829 {
830 DesiredAccess = Entry->Access;
831 }
832 else
833 {
834 DesiredAccess = DuplicateHandleRequest->Access;
835 /* Make sure the source handle has all the desired flags */
836 if ((Entry->Access & DesiredAccess) == 0)
837 {
838 DPRINT1("Handle %p only has access %X; requested %X\n",
839 ConsoleHandle, Entry->Access, DesiredAccess);
840 Status = STATUS_INVALID_PARAMETER;
841 goto Quit;
842 }
843 }
844
845 /* Insert the new handle inside the process handles table */
846 Status = ConSrvInsertObject(ProcessData,
847 &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
848 Entry->Object,
849 DesiredAccess,
850 DuplicateHandleRequest->Inheritable,
851 Entry->ShareMode);
852 if (NT_SUCCESS(Status) &&
853 (DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE))
854 {
855 /* Close the original handle if needed */
856 ConSrvCloseHandleEntry(Entry);
857 }
858
859 Quit:
860 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
861
862 ConSrvReleaseConsole(Console, TRUE);
863 return Status;
864 }
865
866 /* EOF */