2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: consrv/handle.c
5 * PURPOSE: Console I/O Handles functions
6 * PROGRAMMERS: David Welch
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
11 /* INCLUDES *******************************************************************/
15 #include <win/console.h>
20 /* GLOBALS ********************************************************************/
23 typedef struct _CONSOLE_IO_HANDLE
25 PCONSOLE_IO_OBJECT Object
; /* The object on which the handle points to */
29 } CONSOLE_IO_HANDLE
, *PCONSOLE_IO_HANDLE
;
32 /* PRIVATE FUNCTIONS **********************************************************/
35 AdjustHandleCounts(IN PCONSOLE_IO_HANDLE Handle
,
38 PCONSOLE_IO_OBJECT Object
= Handle
->Object
;
40 DPRINT("AdjustHandleCounts(0x%p, %d), Object = 0x%p\n",
41 Handle
, Change
, Object
);
42 DPRINT("\tAdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->ReferenceCount = %d, Object->Type = %lu\n",
43 Handle
, Change
, Object
, Object
->ReferenceCount
, Object
->Type
);
45 if (Handle
->Access
& GENERIC_READ
) Object
->AccessRead
+= Change
;
46 if (Handle
->Access
& GENERIC_WRITE
) Object
->AccessWrite
+= Change
;
47 if (!(Handle
->ShareMode
& FILE_SHARE_READ
)) Object
->ExclusiveRead
+= Change
;
48 if (!(Handle
->ShareMode
& FILE_SHARE_WRITE
)) Object
->ExclusiveWrite
+= Change
;
50 Object
->ReferenceCount
+= Change
;
52 return Object
->ReferenceCount
;
56 ConSrvCloseHandle(IN PCONSOLE_IO_HANDLE Handle
)
58 PCONSOLE_IO_OBJECT Object
= Handle
->Object
;
62 * If this is a input handle, notify and dereference
63 * all the waits related to this handle.
65 if (Object
->Type
== INPUT_BUFFER
)
67 // PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
68 PCONSOLE Console
= Object
->Console
;
71 * Wake up all the writing waiters related to this handle for this
72 * input buffer, if any, then dereference them and purge them all
74 * To select them amongst all the waiters for this input buffer,
75 * pass the handle pointer to the waiters, then they will check
76 * whether or not they are related to this handle and if so, they
79 CsrNotifyWait(&Console
->ReadWaitQueue
,
83 if (!IsListEmpty(&Console
->ReadWaitQueue
))
85 CsrDereferenceWait(&Console
->ReadWaitQueue
);
89 /* If the last handle to a screen buffer is closed, delete it... */
90 if (AdjustHandleCounts(Handle
, -1) == 0)
92 if (Object
->Type
== TEXTMODE_BUFFER
|| Object
->Type
== GRAPHICS_BUFFER
)
94 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
95 /* ...unless it's the only buffer left. Windows allows deletion
96 * even of the last buffer, but having to deal with a lack of
97 * any active buffer might be error-prone. */
98 if (Buffer
->ListEntry
.Flink
!= Buffer
->ListEntry
.Blink
)
99 ConDrvDeleteScreenBuffer(Buffer
);
101 else if (Object
->Type
== INPUT_BUFFER
)
103 DPRINT("Closing the input buffer\n");
107 DPRINT1("Invalid object type %d\n", Object
->Type
);
111 /* Invalidate (zero-out) this handle entry */
112 // Handle->Object = NULL;
113 // RtlZeroMemory(Handle, sizeof(*Handle));
115 RtlZeroMemory(Handle
, sizeof(*Handle
)); // Be sure the whole entry is invalidated.
123 /* Forward declaration, used in ConSrvInitHandlesTable */
124 static VOID
ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData
);
127 ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData
,
129 OUT PHANDLE pInputHandle
,
130 OUT PHANDLE pOutputHandle
,
131 OUT PHANDLE pErrorHandle
)
134 HANDLE InputHandle
= INVALID_HANDLE_VALUE
,
135 OutputHandle
= INVALID_HANDLE_VALUE
,
136 ErrorHandle
= INVALID_HANDLE_VALUE
;
139 * Initialize the handles table. Use temporary variables to store
140 * the handles values in such a way that, if we fail, we don't
141 * return to the caller invalid handle values.
143 * Insert the IO handles.
146 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
148 /* Insert the Input handle */
149 Status
= ConSrvInsertObject(ProcessData
,
151 &Console
->InputBuffer
.Header
,
152 GENERIC_READ
| GENERIC_WRITE
,
154 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
155 if (!NT_SUCCESS(Status
))
157 DPRINT1("Failed to insert the input handle\n");
158 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
159 ConSrvFreeHandlesTable(ProcessData
);
163 /* Insert the Output handle */
164 Status
= ConSrvInsertObject(ProcessData
,
166 &Console
->ActiveBuffer
->Header
,
167 GENERIC_READ
| GENERIC_WRITE
,
169 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
170 if (!NT_SUCCESS(Status
))
172 DPRINT1("Failed to insert the output handle\n");
173 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
174 ConSrvFreeHandlesTable(ProcessData
);
178 /* Insert the Error handle */
179 Status
= ConSrvInsertObject(ProcessData
,
181 &Console
->ActiveBuffer
->Header
,
182 GENERIC_READ
| GENERIC_WRITE
,
184 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
185 if (!NT_SUCCESS(Status
))
187 DPRINT1("Failed to insert the error handle\n");
188 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
189 ConSrvFreeHandlesTable(ProcessData
);
193 /* Return the newly created handles */
194 *pInputHandle
= InputHandle
;
195 *pOutputHandle
= OutputHandle
;
196 *pErrorHandle
= ErrorHandle
;
198 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
199 return STATUS_SUCCESS
;
203 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData
,
204 IN PCONSOLE_PROCESS_DATA TargetProcessData
)
206 NTSTATUS Status
= STATUS_SUCCESS
;
209 RtlEnterCriticalSection(&SourceProcessData
->HandleTableLock
);
211 /* Inherit a handles table only if there is no already */
212 if (TargetProcessData
->HandleTable
!= NULL
/* || TargetProcessData->HandleTableSize != 0 */)
214 Status
= STATUS_UNSUCCESSFUL
;
218 /* Allocate a new handle table for the child process */
219 TargetProcessData
->HandleTable
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
220 SourceProcessData
->HandleTableSize
221 * sizeof(CONSOLE_IO_HANDLE
));
222 if (TargetProcessData
->HandleTable
== NULL
)
224 Status
= STATUS_NO_MEMORY
;
228 TargetProcessData
->HandleTableSize
= SourceProcessData
->HandleTableSize
;
231 * Parse the parent process' handles table and, for each handle,
232 * do a copy of it and reference it, if the handle is inheritable.
234 for (i
= 0, j
= 0; i
< SourceProcessData
->HandleTableSize
; i
++)
236 if (SourceProcessData
->HandleTable
[i
].Object
!= NULL
&&
237 SourceProcessData
->HandleTable
[i
].Inheritable
)
240 * Copy the handle data and increment the reference count of the
241 * pointed object (via the call to ConSrvCreateHandleEntry == AdjustHandleCounts).
243 TargetProcessData
->HandleTable
[j
] = SourceProcessData
->HandleTable
[i
];
244 AdjustHandleCounts(&TargetProcessData
->HandleTable
[j
], +1);
250 RtlLeaveCriticalSection(&SourceProcessData
->HandleTableLock
);
255 ConSrvFreeHandlesTable(IN PCONSOLE_PROCESS_DATA ProcessData
)
257 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
259 if (ProcessData
->HandleTable
!= NULL
)
264 * ProcessData->ConsoleHandle is NULL (and the assertion fails) when
265 * ConSrvFreeHandlesTable is called in ConSrvConnect during the
266 * allocation of a new console.
268 // ASSERT(ProcessData->ConsoleHandle);
269 if (ProcessData
->ConsoleHandle
!= NULL
)
271 /* Close all the console handles */
272 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
274 ConSrvCloseHandle(&ProcessData
->HandleTable
[i
]);
277 /* Free the handles table memory */
278 ConsoleFreeHeap(ProcessData
->HandleTable
);
279 ProcessData
->HandleTable
= NULL
;
282 ProcessData
->HandleTableSize
= 0;
284 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
292 // ConSrvCreateObject
294 ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object
,
295 IN CONSOLE_IO_OBJECT_TYPE Type
,
299 // if (!Object) return;
302 Object
->Console
= Console
;
303 Object
->ReferenceCount
= 0;
305 Object
->AccessRead
= Object
->AccessWrite
= 0;
306 Object
->ExclusiveRead
= Object
->ExclusiveWrite
= 0;
310 ConSrvInsertObject(IN PCONSOLE_PROCESS_DATA ProcessData
,
312 IN PCONSOLE_IO_OBJECT Object
,
314 IN BOOLEAN Inheritable
,
317 #define IO_HANDLES_INCREMENT 2 * 3
320 PCONSOLE_IO_HANDLE Block
;
322 // NOTE: Commented out because calling code always lock HandleTableLock before.
323 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
325 ASSERT( (ProcessData
->HandleTable
== NULL
&& ProcessData
->HandleTableSize
== 0) ||
326 (ProcessData
->HandleTable
!= NULL
&& ProcessData
->HandleTableSize
!= 0) );
328 if (ProcessData
->HandleTable
)
330 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
332 if (ProcessData
->HandleTable
[i
].Object
== NULL
)
337 if (i
>= ProcessData
->HandleTableSize
)
339 /* Allocate a new handles table */
340 Block
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
341 (ProcessData
->HandleTableSize
+
342 IO_HANDLES_INCREMENT
) * sizeof(CONSOLE_IO_HANDLE
));
345 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
346 return STATUS_UNSUCCESSFUL
;
349 /* If we previously had a handles table, free it and use the new one */
350 if (ProcessData
->HandleTable
)
352 /* Copy the handles from the old table to the new one */
354 ProcessData
->HandleTable
,
355 ProcessData
->HandleTableSize
* sizeof(CONSOLE_IO_HANDLE
));
356 ConsoleFreeHeap(ProcessData
->HandleTable
);
358 ProcessData
->HandleTable
= Block
;
359 ProcessData
->HandleTableSize
+= IO_HANDLES_INCREMENT
;
362 ProcessData
->HandleTable
[i
].Object
= Object
;
363 ProcessData
->HandleTable
[i
].Access
= Access
;
364 ProcessData
->HandleTable
[i
].Inheritable
= Inheritable
;
365 ProcessData
->HandleTable
[i
].ShareMode
= ShareMode
;
366 AdjustHandleCounts(&ProcessData
->HandleTable
[i
], +1);
367 *Handle
= ULongToHandle((i
<< 2) | 0x3);
369 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
371 return STATUS_SUCCESS
;
375 ConSrvRemoveObject(IN PCONSOLE_PROCESS_DATA ProcessData
,
378 ULONG Index
= HandleToULong(Handle
) >> 2;
380 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
382 ASSERT(ProcessData
->HandleTable
);
383 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
384 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
386 if (Index
>= ProcessData
->HandleTableSize
||
387 ProcessData
->HandleTable
[Index
].Object
== NULL
)
389 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
390 return STATUS_INVALID_HANDLE
;
393 ASSERT(ProcessData
->ConsoleHandle
);
394 ConSrvCloseHandle(&ProcessData
->HandleTable
[Index
]);
396 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
397 return STATUS_SUCCESS
;
401 ConSrvGetObject(IN PCONSOLE_PROCESS_DATA ProcessData
,
403 OUT PCONSOLE_IO_OBJECT
* Object
,
404 OUT PVOID
* Entry OPTIONAL
,
406 IN BOOLEAN LockConsole
,
407 IN CONSOLE_IO_OBJECT_TYPE Type
)
410 ULONG Index
= HandleToULong(Handle
) >> 2;
411 PCONSOLE_IO_HANDLE HandleEntry
= NULL
;
412 PCONSOLE_IO_OBJECT ObjectEntry
= NULL
;
413 // PCONSOLE ObjectConsole;
416 if (Entry
) *Entry
= NULL
;
418 DPRINT("ConSrvGetObject -- Object: 0x%x, Handle: 0x%x\n", Object
, Handle
);
420 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
422 if ( IsConsoleHandle(Handle
) &&
423 Index
< ProcessData
->HandleTableSize
)
425 HandleEntry
= &ProcessData
->HandleTable
[Index
];
426 ObjectEntry
= HandleEntry
->Object
;
429 if ( HandleEntry
== NULL
||
430 ObjectEntry
== NULL
||
431 (HandleEntry
->Access
& Access
) == 0 ||
432 /*(Type != 0 && ObjectEntry->Type != Type)*/
433 (Type
!= 0 && (ObjectEntry
->Type
& Type
) == 0) )
435 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",
436 Handle
, Type
, Access
, ObjectEntry
, HandleEntry
, (ObjectEntry
? ObjectEntry
->Type
: 0), (HandleEntry
? HandleEntry
->Access
: 0));
438 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
439 return STATUS_INVALID_HANDLE
;
442 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
444 // Status = ConSrvGetConsole(ProcessData, &ObjectConsole, LockConsole);
445 // if (NT_SUCCESS(Status))
446 if (ConDrvValidateConsoleUnsafe(ObjectEntry
->Console
, CONSOLE_RUNNING
, LockConsole
))
448 _InterlockedIncrement(&ObjectEntry
->Console
->ReferenceCount
);
450 /* Return the objects to the caller */
451 *Object
= ObjectEntry
;
452 if (Entry
) *Entry
= HandleEntry
;
454 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
455 return STATUS_SUCCESS
;
459 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
460 return STATUS_INVALID_HANDLE
;
465 ConSrvReleaseObject(IN PCONSOLE_IO_OBJECT Object
,
466 IN BOOLEAN IsConsoleLocked
)
468 ConSrvReleaseConsole(Object
->Console
, IsConsoleLocked
);
474 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData
,
475 PHANDLE pInputHandle
,
476 PHANDLE pOutputHandle
,
477 PHANDLE pErrorHandle
,
478 PCONSOLE_INIT_INFO ConsoleInitInfo
)
480 NTSTATUS Status
= STATUS_SUCCESS
;
481 HANDLE ConsoleHandle
;
482 PCONSRV_CONSOLE Console
;
485 * We are about to create a new console. However when ConSrvNewProcess
486 * was called, we didn't know that we wanted to create a new console and
487 * therefore, we by default inherited the handles table from our parent
488 * process. It's only now that we notice that in fact we do not need
489 * them, because we've created a new console and thus we must use it.
491 * Therefore, free the handles table so that we can recreate
492 * a new one later on.
494 ConSrvFreeHandlesTable(ProcessData
);
496 /* Initialize a new Console owned by this process */
497 DPRINT("Initialization of console '%S' for process '%S' on desktop '%S'\n",
498 ConsoleInitInfo
->ConsoleTitle
? ConsoleInitInfo
->ConsoleTitle
: L
"n/a",
499 ConsoleInitInfo
->AppName
? ConsoleInitInfo
->AppName
: L
"n/a",
500 ConsoleInitInfo
->Desktop
? ConsoleInitInfo
->Desktop
: L
"n/a");
501 Status
= ConSrvInitConsole(&ConsoleHandle
,
504 ProcessData
->Process
);
505 if (!NT_SUCCESS(Status
))
507 DPRINT1("Console initialization failed\n");
511 /* Assign the new console handle */
512 ProcessData
->ConsoleHandle
= ConsoleHandle
;
514 /* Initialize the handles table */
515 Status
= ConSrvInitHandlesTable(ProcessData
,
520 if (!NT_SUCCESS(Status
))
522 DPRINT1("Failed to initialize the handles table\n");
523 ConSrvDeleteConsole(Console
);
524 ProcessData
->ConsoleHandle
= NULL
;
528 /* Duplicate the Initialization Events */
529 Status
= NtDuplicateObject(NtCurrentProcess(),
530 Console
->InitEvents
[INIT_SUCCESS
],
531 ProcessData
->Process
->ProcessHandle
,
532 &ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
],
533 EVENT_ALL_ACCESS
, 0, 0);
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status
);
537 ConSrvFreeHandlesTable(ProcessData
);
538 ConSrvDeleteConsole(Console
);
539 ProcessData
->ConsoleHandle
= NULL
;
543 Status
= NtDuplicateObject(NtCurrentProcess(),
544 Console
->InitEvents
[INIT_FAILURE
],
545 ProcessData
->Process
->ProcessHandle
,
546 &ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_FAILURE
],
547 EVENT_ALL_ACCESS
, 0, 0);
548 if (!NT_SUCCESS(Status
))
550 DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status
);
551 NtClose(ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
]);
552 ConSrvFreeHandlesTable(ProcessData
);
553 ConSrvDeleteConsole(Console
);
554 ProcessData
->ConsoleHandle
= NULL
;
558 /* Duplicate the Input Event */
559 Status
= NtDuplicateObject(NtCurrentProcess(),
560 Console
->InputBuffer
.ActiveEvent
,
561 ProcessData
->Process
->ProcessHandle
,
562 &ConsoleInitInfo
->ConsoleStartInfo
->InputWaitHandle
,
563 EVENT_ALL_ACCESS
, 0, 0);
564 if (!NT_SUCCESS(Status
))
566 DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status
);
567 NtClose(ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_FAILURE
]);
568 NtClose(ConsoleInitInfo
->ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
]);
569 ConSrvFreeHandlesTable(ProcessData
);
570 ConSrvDeleteConsole(Console
);
571 ProcessData
->ConsoleHandle
= NULL
;
575 /* Mark the process as having a console */
576 ProcessData
->ConsoleApp
= TRUE
;
577 ProcessData
->Process
->Flags
|= CsrProcessIsConsoleApp
;
579 /* Return the console handle to the caller */
580 ConsoleInitInfo
->ConsoleStartInfo
->ConsoleHandle
= ProcessData
->ConsoleHandle
;
582 /* Insert the process into the processes list of the console */
583 InsertHeadList(&Console
->ProcessList
, &ProcessData
->ConsoleLink
);
585 /* Add a reference count because the process is tied to the console */
586 _InterlockedIncrement(&Console
->ReferenceCount
);
588 /* Update the internal info of the terminal */
589 TermRefreshInternalInfo(Console
);
591 return STATUS_SUCCESS
;
595 ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData
,
596 HANDLE ConsoleHandle
,
597 BOOLEAN CreateNewHandlesTable
,
598 PHANDLE pInputHandle
,
599 PHANDLE pOutputHandle
,
600 PHANDLE pErrorHandle
,
601 PCONSOLE_START_INFO ConsoleStartInfo
)
603 NTSTATUS Status
= STATUS_SUCCESS
;
606 /* Validate and lock the console */
607 if (!ConSrvValidateConsole(&Console
,
609 CONSOLE_RUNNING
, TRUE
))
611 // FIXME: Find another status code
612 return STATUS_UNSUCCESSFUL
;
615 /* Inherit the console */
616 ProcessData
->ConsoleHandle
= ConsoleHandle
;
618 if (CreateNewHandlesTable
)
621 * We are about to create a new console. However when ConSrvNewProcess
622 * was called, we didn't know that we wanted to create a new console and
623 * therefore, we by default inherited the handles table from our parent
624 * process. It's only now that we notice that in fact we do not need
625 * them, because we've created a new console and thus we must use it.
627 * Therefore, free the handles table so that we can recreate
628 * a new one later on.
630 ConSrvFreeHandlesTable(ProcessData
);
632 /* Initialize the handles table */
633 Status
= ConSrvInitHandlesTable(ProcessData
,
638 if (!NT_SUCCESS(Status
))
640 DPRINT1("Failed to initialize the handles table\n");
641 ProcessData
->ConsoleHandle
= NULL
;
646 /* Duplicate the Initialization Events */
647 Status
= NtDuplicateObject(NtCurrentProcess(),
648 Console
->InitEvents
[INIT_SUCCESS
],
649 ProcessData
->Process
->ProcessHandle
,
650 &ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
],
651 EVENT_ALL_ACCESS
, 0, 0);
652 if (!NT_SUCCESS(Status
))
654 DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status
);
655 ConSrvFreeHandlesTable(ProcessData
);
656 ProcessData
->ConsoleHandle
= NULL
;
660 Status
= NtDuplicateObject(NtCurrentProcess(),
661 Console
->InitEvents
[INIT_FAILURE
],
662 ProcessData
->Process
->ProcessHandle
,
663 &ConsoleStartInfo
->InitEvents
[INIT_FAILURE
],
664 EVENT_ALL_ACCESS
, 0, 0);
665 if (!NT_SUCCESS(Status
))
667 DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status
);
668 NtClose(ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
]);
669 ConSrvFreeHandlesTable(ProcessData
);
670 ProcessData
->ConsoleHandle
= NULL
;
674 /* Duplicate the Input Event */
675 Status
= NtDuplicateObject(NtCurrentProcess(),
676 Console
->InputBuffer
.ActiveEvent
,
677 ProcessData
->Process
->ProcessHandle
,
678 &ConsoleStartInfo
->InputWaitHandle
,
679 EVENT_ALL_ACCESS
, 0, 0);
680 if (!NT_SUCCESS(Status
))
682 DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status
);
683 NtClose(ConsoleStartInfo
->InitEvents
[INIT_FAILURE
]);
684 NtClose(ConsoleStartInfo
->InitEvents
[INIT_SUCCESS
]);
685 ConSrvFreeHandlesTable(ProcessData
); // NOTE: Always free the handles table.
686 ProcessData
->ConsoleHandle
= NULL
;
690 /* Mark the process as having a console */
691 ProcessData
->ConsoleApp
= TRUE
;
692 ProcessData
->Process
->Flags
|= CsrProcessIsConsoleApp
;
694 /* Return the console handle to the caller */
695 ConsoleStartInfo
->ConsoleHandle
= ProcessData
->ConsoleHandle
;
697 /* Insert the process into the processes list of the console */
698 InsertHeadList(&Console
->ProcessList
, &ProcessData
->ConsoleLink
);
700 /* Add a reference count because the process is tied to the console */
701 _InterlockedIncrement(&Console
->ReferenceCount
);
703 /* Update the internal info of the terminal */
704 TermRefreshInternalInfo(Console
);
706 Status
= STATUS_SUCCESS
;
709 /* Unlock the console and return */
710 LeaveCriticalSection(&Console
->Lock
);
715 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData
)
718 PCONSOLE_PROCESS_DATA ConsoleLeaderProcess
;
720 DPRINT("ConSrvRemoveConsole\n");
722 /* Mark the process as not having a console anymore */
723 ProcessData
->ConsoleApp
= FALSE
;
724 ProcessData
->Process
->Flags
&= ~CsrProcessIsConsoleApp
;
726 /* Validate and lock the console */
727 if (!ConSrvValidateConsole(&Console
,
728 ProcessData
->ConsoleHandle
,
729 CONSOLE_RUNNING
, TRUE
))
731 // FIXME: Find another status code
732 return STATUS_UNSUCCESSFUL
;
735 DPRINT("ConSrvRemoveConsole - Locking OK\n");
737 /* Retrieve the console leader process */
738 ConsoleLeaderProcess
= ConSrvGetConsoleLeaderProcess(Console
);
740 /* Close all console handles and free the handles table */
741 ConSrvFreeHandlesTable(ProcessData
);
743 /* Detach the process from the console */
744 ProcessData
->ConsoleHandle
= NULL
;
746 /* Remove the process from the console's list of processes */
747 RemoveEntryList(&ProcessData
->ConsoleLink
);
749 /* Check whether the console should send a last close notification */
750 if (Console
->NotifyLastClose
)
752 /* If we are removing the process which wants the last close notification... */
753 if (ProcessData
== Console
->NotifiedLastCloseProcess
)
755 /* ... just reset the flag and the pointer... */
756 Console
->NotifyLastClose
= FALSE
;
757 Console
->NotifiedLastCloseProcess
= NULL
;
760 * ... otherwise, if we are removing the console leader process
761 * (that cannot be the process wanting the notification, because
762 * the previous case already dealt with it)...
764 else if (ProcessData
== ConsoleLeaderProcess
)
767 * ... reset the flag first (so that we avoid multiple notifications)
768 * and then send the last close notification.
770 Console
->NotifyLastClose
= FALSE
;
771 ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT
, Console
->NotifiedLastCloseProcess
);
773 /* Only now, reset the pointer */
774 Console
->NotifiedLastCloseProcess
= NULL
;
778 /* Update the internal info of the terminal */
779 TermRefreshInternalInfo(Console
);
781 /* Release the console */
782 DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console
->ReferenceCount
);
783 ConSrvReleaseConsole(Console
, TRUE
);
785 return STATUS_SUCCESS
;
789 /* PUBLIC SERVER APIS *********************************************************/
791 CSR_API(SrvOpenConsole
)
794 * This API opens a handle to either the input buffer or to
795 * a screen-buffer of the console of the current process.
799 PCONSOLE_OPENCONSOLE OpenConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.OpenConsoleRequest
;
800 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
803 DWORD DesiredAccess
= OpenConsoleRequest
->DesiredAccess
;
804 DWORD ShareMode
= OpenConsoleRequest
->ShareMode
;
805 PCONSOLE_IO_OBJECT Object
;
807 OpenConsoleRequest
->Handle
= INVALID_HANDLE_VALUE
;
809 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
810 if (!NT_SUCCESS(Status
))
812 DPRINT1("Can't get console\n");
816 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
819 * Open a handle to either the active screen buffer or the input buffer.
821 if (OpenConsoleRequest
->HandleType
== HANDLE_OUTPUT
)
823 Object
= &Console
->ActiveBuffer
->Header
;
827 Object
= &Console
->InputBuffer
.Header
;
830 if (((DesiredAccess
& GENERIC_READ
) && Object
->ExclusiveRead
!= 0) ||
831 ((DesiredAccess
& GENERIC_WRITE
) && Object
->ExclusiveWrite
!= 0) ||
832 (!(ShareMode
& FILE_SHARE_READ
) && Object
->AccessRead
!= 0) ||
833 (!(ShareMode
& FILE_SHARE_WRITE
) && Object
->AccessWrite
!= 0))
835 DPRINT1("Sharing violation\n");
836 Status
= STATUS_SHARING_VIOLATION
;
840 Status
= ConSrvInsertObject(ProcessData
,
841 &OpenConsoleRequest
->Handle
,
844 OpenConsoleRequest
->InheritHandle
,
848 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
850 ConSrvReleaseConsole(Console
, TRUE
);
854 CSR_API(SrvDuplicateHandle
)
857 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.DuplicateHandleRequest
;
858 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
861 HANDLE SourceHandle
= DuplicateHandleRequest
->SourceHandle
;
862 ULONG Index
= HandleToULong(SourceHandle
) >> 2;
863 PCONSOLE_IO_HANDLE Entry
;
866 DuplicateHandleRequest
->TargetHandle
= INVALID_HANDLE_VALUE
;
868 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
869 if (!NT_SUCCESS(Status
))
871 DPRINT1("Can't get console\n");
875 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
877 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
878 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
880 if ( /** !IsConsoleHandle(SourceHandle) || **/
881 Index
>= ProcessData
->HandleTableSize
||
882 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
884 DPRINT1("Couldn't duplicate invalid handle 0x%p\n", SourceHandle
);
885 Status
= STATUS_INVALID_HANDLE
;
889 if (DuplicateHandleRequest
->Options
& DUPLICATE_SAME_ACCESS
)
891 DesiredAccess
= Entry
->Access
;
895 DesiredAccess
= DuplicateHandleRequest
->DesiredAccess
;
896 /* Make sure the source handle has all the desired flags */
897 if ((Entry
->Access
& DesiredAccess
) == 0)
899 DPRINT1("Handle 0x%p only has access %X; requested %X\n",
900 SourceHandle
, Entry
->Access
, DesiredAccess
);
901 Status
= STATUS_INVALID_PARAMETER
;
906 /* Insert the new handle inside the process handles table */
907 Status
= ConSrvInsertObject(ProcessData
,
908 &DuplicateHandleRequest
->TargetHandle
,
911 DuplicateHandleRequest
->InheritHandle
,
913 if (NT_SUCCESS(Status
) &&
914 (DuplicateHandleRequest
->Options
& DUPLICATE_CLOSE_SOURCE
))
916 /* Close the original handle if needed */
917 ConSrvCloseHandle(Entry
);
921 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
923 ConSrvReleaseConsole(Console
, TRUE
);
927 CSR_API(SrvGetHandleInformation
)
930 PCONSOLE_GETHANDLEINFO GetHandleInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetHandleInfoRequest
;
931 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
934 HANDLE Handle
= GetHandleInfoRequest
->Handle
;
935 ULONG Index
= HandleToULong(Handle
) >> 2;
936 PCONSOLE_IO_HANDLE Entry
;
938 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
939 if (!NT_SUCCESS(Status
))
941 DPRINT1("Can't get console\n");
945 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
947 ASSERT(ProcessData
->HandleTable
);
948 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
949 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
951 if (!IsConsoleHandle(Handle
) ||
952 Index
>= ProcessData
->HandleTableSize
||
953 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
955 Status
= STATUS_INVALID_HANDLE
;
960 * Retrieve the handle information flags. The console server
961 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
963 GetHandleInfoRequest
->Flags
= 0;
964 if (Entry
->Inheritable
) GetHandleInfoRequest
->Flags
|= HANDLE_FLAG_INHERIT
;
966 Status
= STATUS_SUCCESS
;
969 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
971 ConSrvReleaseConsole(Console
, TRUE
);
975 CSR_API(SrvSetHandleInformation
)
978 PCONSOLE_SETHANDLEINFO SetHandleInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHandleInfoRequest
;
979 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
982 HANDLE Handle
= SetHandleInfoRequest
->Handle
;
983 ULONG Index
= HandleToULong(Handle
) >> 2;
984 PCONSOLE_IO_HANDLE Entry
;
986 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
987 if (!NT_SUCCESS(Status
))
989 DPRINT1("Can't get console\n");
993 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
995 ASSERT(ProcessData
->HandleTable
);
996 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
997 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
999 if (!IsConsoleHandle(Handle
) ||
1000 Index
>= ProcessData
->HandleTableSize
||
1001 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
1003 Status
= STATUS_INVALID_HANDLE
;
1008 * Modify the handle information flags. The console server
1009 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
1011 if (SetHandleInfoRequest
->Mask
& HANDLE_FLAG_INHERIT
)
1013 Entry
->Inheritable
= ((SetHandleInfoRequest
->Flags
& HANDLE_FLAG_INHERIT
) != 0);
1016 Status
= STATUS_SUCCESS
;
1019 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
1021 ConSrvReleaseConsole(Console
, TRUE
);
1025 CSR_API(SrvCloseHandle
)
1028 PCONSOLE_CLOSEHANDLE CloseHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CloseHandleRequest
;
1029 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1032 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1033 if (!NT_SUCCESS(Status
))
1035 DPRINT1("Can't get console\n");
1039 Status
= ConSrvRemoveObject(ProcessData
, CloseHandleRequest
->Handle
);
1041 ConSrvReleaseConsole(Console
, TRUE
);
1045 CSR_API(SrvVerifyConsoleIoHandle
)
1048 PCONSOLE_VERIFYHANDLE VerifyHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.VerifyHandleRequest
;
1049 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1052 HANDLE IoHandle
= VerifyHandleRequest
->Handle
;
1053 ULONG Index
= HandleToULong(IoHandle
) >> 2;
1055 VerifyHandleRequest
->IsValid
= FALSE
;
1057 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1058 if (!NT_SUCCESS(Status
))
1060 DPRINT1("Can't get console\n");
1064 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
1066 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
1067 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
1069 if (!IsConsoleHandle(IoHandle
) ||
1070 Index
>= ProcessData
->HandleTableSize
||
1071 ProcessData
->HandleTable
[Index
].Object
== NULL
)
1073 DPRINT("SrvVerifyConsoleIoHandle failed\n");
1077 VerifyHandleRequest
->IsValid
= TRUE
;
1080 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
1082 ConSrvReleaseConsole(Console
, TRUE
);
1083 return STATUS_SUCCESS
;