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
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
11 /* INCLUDES *******************************************************************/
15 #include <win/console.h>
20 /* GLOBALS ********************************************************************/
22 typedef struct _CONSOLE_IO_HANDLE
24 PCONSOLE_IO_OBJECT Object
; /* The object on which the handle points to */
28 } CONSOLE_IO_HANDLE
, *PCONSOLE_IO_HANDLE
;
31 /* PRIVATE FUNCTIONS **********************************************************/
34 AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry
, INT Change
)
36 PCONSOLE_IO_OBJECT Object
= Entry
->Object
;
38 DPRINT("AdjustHandleCounts(0x%p, %d), Object = 0x%p\n", Entry
, Change
, Object
);
39 DPRINT("\tAdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry
, Change
, Object
, Object
->HandleCount
, Object
->Type
);
41 if (Entry
->Access
& GENERIC_READ
) Object
->AccessRead
+= Change
;
42 if (Entry
->Access
& GENERIC_WRITE
) Object
->AccessWrite
+= Change
;
43 if (!(Entry
->ShareMode
& FILE_SHARE_READ
)) Object
->ExclusiveRead
+= Change
;
44 if (!(Entry
->ShareMode
& FILE_SHARE_WRITE
)) Object
->ExclusiveWrite
+= Change
;
46 Object
->HandleCount
+= Change
;
48 return Object
->HandleCount
;
52 ConSrvCreateHandleEntry(PCONSOLE_IO_HANDLE Entry
)
54 /// LOCK /// PCONSOLE_IO_OBJECT Object = Entry->Object;
55 /// LOCK /// EnterCriticalSection(&Object->Console->Lock);
56 AdjustHandleCounts(Entry
, +1);
57 /// LOCK /// LeaveCriticalSection(&Object->Console->Lock);
61 ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry
)
63 PCONSOLE_IO_OBJECT Object
= Entry
->Object
;
66 /// LOCK /// PCONSOLE Console = Object->Console;
67 /// LOCK /// EnterCriticalSection(&Console->Lock);
70 * If this is a input handle, notify and dereference
71 * all the waits related to this handle.
73 if (Object
->Type
== INPUT_BUFFER
)
75 // PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
76 PCONSOLE Console
= Object
->Console
;
79 * Wake up all the writing waiters related to this handle for this
80 * input buffer, if any, then dereference them and purge them all
82 * To select them amongst all the waiters for this input buffer,
83 * pass the handle pointer to the waiters, then they will check
84 * whether or not they are related to this handle and if so, they
87 CsrNotifyWait(&Console
->ReadWaitQueue
,
91 if (!IsListEmpty(&Console
->ReadWaitQueue
))
93 CsrDereferenceWait(&Console
->ReadWaitQueue
);
97 /* If the last handle to a screen buffer is closed, delete it... */
98 if (AdjustHandleCounts(Entry
, -1) == 0)
100 if (Object
->Type
== TEXTMODE_BUFFER
|| Object
->Type
== GRAPHICS_BUFFER
)
102 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
103 /* ...unless it's the only buffer left. Windows allows deletion
104 * even of the last buffer, but having to deal with a lack of
105 * any active buffer might be error-prone. */
106 if (Buffer
->ListEntry
.Flink
!= Buffer
->ListEntry
.Blink
)
107 ConioDeleteScreenBuffer(Buffer
);
109 else if (Object
->Type
== INPUT_BUFFER
)
111 DPRINT("Closing the input buffer\n");
115 DPRINT1("Invalid object type %d\n", Object
->Type
);
119 /// LOCK /// LeaveCriticalSection(&Console->Lock);
121 /* Invalidate (zero-out) this handle entry */
122 // Entry->Object = NULL;
123 // RtlZeroMemory(Entry, sizeof(*Entry));
125 RtlZeroMemory(Entry
, sizeof(*Entry
)); // Be sure the whole entry is invalidated.
129 /* Forward declaration, used in ConSrvInitHandlesTable */
130 static VOID
ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData
);
133 ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData
,
135 OUT PHANDLE pInputHandle
,
136 OUT PHANDLE pOutputHandle
,
137 OUT PHANDLE pErrorHandle
)
140 HANDLE InputHandle
= INVALID_HANDLE_VALUE
,
141 OutputHandle
= INVALID_HANDLE_VALUE
,
142 ErrorHandle
= INVALID_HANDLE_VALUE
;
145 * Initialize the handles table. Use temporary variables to store
146 * the handles values in such a way that, if we fail, we don't
147 * return to the caller invalid handle values.
149 * Insert the IO handles.
152 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
154 /* Insert the Input handle */
155 Status
= ConSrvInsertObject(ProcessData
,
157 &Console
->InputBuffer
.Header
,
158 GENERIC_READ
| GENERIC_WRITE
,
160 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
161 if (!NT_SUCCESS(Status
))
163 DPRINT1("Failed to insert the input handle\n");
164 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
165 ConSrvFreeHandlesTable(ProcessData
);
169 /* Insert the Output handle */
170 Status
= ConSrvInsertObject(ProcessData
,
172 &Console
->ActiveBuffer
->Header
,
173 GENERIC_READ
| GENERIC_WRITE
,
175 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
176 if (!NT_SUCCESS(Status
))
178 DPRINT1("Failed to insert the output handle\n");
179 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
180 ConSrvFreeHandlesTable(ProcessData
);
184 /* Insert the Error handle */
185 Status
= ConSrvInsertObject(ProcessData
,
187 &Console
->ActiveBuffer
->Header
,
188 GENERIC_READ
| GENERIC_WRITE
,
190 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
191 if (!NT_SUCCESS(Status
))
193 DPRINT1("Failed to insert the error handle\n");
194 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
195 ConSrvFreeHandlesTable(ProcessData
);
199 /* Return the newly created handles */
200 *pInputHandle
= InputHandle
;
201 *pOutputHandle
= OutputHandle
;
202 *pErrorHandle
= ErrorHandle
;
204 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
205 return STATUS_SUCCESS
;
209 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData
,
210 IN PCONSOLE_PROCESS_DATA TargetProcessData
)
212 NTSTATUS Status
= STATUS_SUCCESS
;
215 RtlEnterCriticalSection(&SourceProcessData
->HandleTableLock
);
217 /* Inherit a handles table only if there is no already */
218 if (TargetProcessData
->HandleTable
!= NULL
/* || TargetProcessData->HandleTableSize != 0 */)
220 Status
= STATUS_UNSUCCESSFUL
;
224 /* Allocate a new handle table for the child process */
225 TargetProcessData
->HandleTable
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
226 SourceProcessData
->HandleTableSize
227 * sizeof(CONSOLE_IO_HANDLE
));
228 if (TargetProcessData
->HandleTable
== NULL
)
230 Status
= STATUS_NO_MEMORY
;
234 TargetProcessData
->HandleTableSize
= SourceProcessData
->HandleTableSize
;
237 * Parse the parent process' handles table and, for each handle,
238 * do a copy of it and reference it, if the handle is inheritable.
240 for (i
= 0, j
= 0; i
< SourceProcessData
->HandleTableSize
; i
++)
242 if (SourceProcessData
->HandleTable
[i
].Object
!= NULL
&&
243 SourceProcessData
->HandleTable
[i
].Inheritable
)
246 * Copy the handle data and increment the reference count of the
247 * pointed object (via the call to ConSrvCreateHandleEntry).
249 TargetProcessData
->HandleTable
[j
] = SourceProcessData
->HandleTable
[i
];
250 ConSrvCreateHandleEntry(&TargetProcessData
->HandleTable
[j
]);
256 RtlLeaveCriticalSection(&SourceProcessData
->HandleTableLock
);
261 ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData
)
263 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
265 if (ProcessData
->HandleTable
!= NULL
)
270 * ProcessData->ConsoleHandle is NULL (and the assertion fails) when
271 * ConSrvFreeHandlesTable is called in ConSrvConnect during the
272 * allocation of a new console.
274 // ASSERT(ProcessData->ConsoleHandle);
275 if (ProcessData
->ConsoleHandle
!= NULL
)
277 /* Close all the console handles */
278 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
280 ConSrvCloseHandleEntry(&ProcessData
->HandleTable
[i
]);
283 /* Free the handles table memory */
284 ConsoleFreeHeap(ProcessData
->HandleTable
);
285 ProcessData
->HandleTable
= NULL
;
288 ProcessData
->HandleTableSize
= 0;
290 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
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
->AccessRead
= Object
->AccessWrite
= 0;
304 Object
->ExclusiveRead
= Object
->ExclusiveWrite
= 0;
305 Object
->HandleCount
= 0;
309 ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData
,
311 PCONSOLE_IO_OBJECT Object
,
316 #define IO_HANDLES_INCREMENT 2 * 3
319 PCONSOLE_IO_HANDLE Block
;
321 // NOTE: Commented out because calling code always lock HandleTableLock before.
322 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
324 ASSERT( (ProcessData
->HandleTable
== NULL
&& ProcessData
->HandleTableSize
== 0) ||
325 (ProcessData
->HandleTable
!= NULL
&& ProcessData
->HandleTableSize
!= 0) );
327 if (ProcessData
->HandleTable
)
329 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
331 if (ProcessData
->HandleTable
[i
].Object
== NULL
)
336 if (i
>= ProcessData
->HandleTableSize
)
338 /* Allocate a new handles table */
339 Block
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
340 (ProcessData
->HandleTableSize
+
341 IO_HANDLES_INCREMENT
) * sizeof(CONSOLE_IO_HANDLE
));
344 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
345 return STATUS_UNSUCCESSFUL
;
348 /* If we previously had a handles table, free it and use the new one */
349 if (ProcessData
->HandleTable
)
351 /* Copy the handles from the old table to the new one */
353 ProcessData
->HandleTable
,
354 ProcessData
->HandleTableSize
* sizeof(CONSOLE_IO_HANDLE
));
355 ConsoleFreeHeap(ProcessData
->HandleTable
);
357 ProcessData
->HandleTable
= Block
;
358 ProcessData
->HandleTableSize
+= IO_HANDLES_INCREMENT
;
361 ProcessData
->HandleTable
[i
].Object
= Object
;
362 ProcessData
->HandleTable
[i
].Access
= Access
;
363 ProcessData
->HandleTable
[i
].Inheritable
= Inheritable
;
364 ProcessData
->HandleTable
[i
].ShareMode
= ShareMode
;
365 ConSrvCreateHandleEntry(&ProcessData
->HandleTable
[i
]);
366 *Handle
= ULongToHandle((i
<< 2) | 0x3);
368 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
370 return STATUS_SUCCESS
;
374 ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData
,
377 ULONG Index
= HandleToULong(Handle
) >> 2;
379 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
381 ASSERT(ProcessData
->HandleTable
);
382 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
383 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
385 if (Index
>= ProcessData
->HandleTableSize
||
386 ProcessData
->HandleTable
[Index
].Object
== NULL
)
388 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
389 return STATUS_INVALID_HANDLE
;
392 ASSERT(ProcessData
->ConsoleHandle
);
393 ConSrvCloseHandleEntry(&ProcessData
->HandleTable
[Index
]);
395 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
396 return STATUS_SUCCESS
;
400 ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData
,
402 PCONSOLE_IO_OBJECT
* Object
,
403 PVOID
* Entry OPTIONAL
,
406 CONSOLE_IO_OBJECT_TYPE Type
)
409 ULONG Index
= HandleToULong(Handle
) >> 2;
410 PCONSOLE_IO_HANDLE HandleEntry
= NULL
;
411 PCONSOLE_IO_OBJECT ObjectEntry
= NULL
;
412 // PCONSOLE ObjectConsole;
415 if (Entry
) *Entry
= NULL
;
417 DPRINT("ConSrvGetObject -- Object: 0x%x, Handle: 0x%x\n", Object
, Handle
);
419 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
421 if ( IsConsoleHandle(Handle
) &&
422 Index
< ProcessData
->HandleTableSize
)
424 HandleEntry
= &ProcessData
->HandleTable
[Index
];
425 ObjectEntry
= HandleEntry
->Object
;
428 if ( HandleEntry
== NULL
||
429 ObjectEntry
== NULL
||
430 (HandleEntry
->Access
& Access
) == 0 ||
431 /*(Type != 0 && ObjectEntry->Type != Type)*/
432 (Type
!= 0 && (ObjectEntry
->Type
& Type
) == 0) )
434 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",
435 Handle
, Type
, Access
, ObjectEntry
, HandleEntry
, (ObjectEntry
? ObjectEntry
->Type
: 0), (HandleEntry
? HandleEntry
->Access
: 0));
437 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
438 return STATUS_INVALID_HANDLE
;
441 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
443 // Status = ConSrvGetConsole(ProcessData, &ObjectConsole, LockConsole);
444 // if (NT_SUCCESS(Status))
445 if (ConDrvValidateConsoleUnsafe(ObjectEntry
->Console
, CONSOLE_RUNNING
, LockConsole
))
447 _InterlockedIncrement(&ObjectEntry
->Console
->ReferenceCount
);
449 /* Return the objects to the caller */
450 *Object
= ObjectEntry
;
451 if (Entry
) *Entry
= HandleEntry
;
453 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
454 return STATUS_SUCCESS
;
458 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
459 return STATUS_INVALID_HANDLE
;
464 ConSrvReleaseObject(PCONSOLE_IO_OBJECT Object
,
465 BOOL IsConsoleLocked
)
467 ConSrvReleaseConsole(Object
->Console
, IsConsoleLocked
);
471 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData
,
472 PHANDLE pInputHandle
,
473 PHANDLE pOutputHandle
,
474 PHANDLE pErrorHandle
,
475 PCONSOLE_START_INFO ConsoleStartInfo
)
477 NTSTATUS Status
= STATUS_SUCCESS
;
478 HANDLE ConsoleHandle
;
482 * We are about to create a new console. However when ConSrvNewProcess
483 * was called, we didn't know that we wanted to create a new console and
484 * therefore, we by default inherited the handles table from our parent
485 * process. It's only now that we notice that in fact we do not need
486 * them, because we've created a new console and thus we must use it.
488 * Therefore, free the handles table so that we can recreate
489 * a new one later on.
491 ConSrvFreeHandlesTable(ProcessData
);
493 /* Initialize a new Console owned by this process */
494 Status
= ConSrvInitConsole(&ConsoleHandle
,
497 HandleToUlong(ProcessData
->Process
->ClientId
.UniqueProcess
));
498 if (!NT_SUCCESS(Status
))
500 DPRINT1("Console initialization failed\n");
504 /* Assign the new console handle */
505 ProcessData
->ConsoleHandle
= ConsoleHandle
;
507 /* Initialize the handles table */
508 Status
= ConSrvInitHandlesTable(ProcessData
,
513 if (!NT_SUCCESS(Status
))
515 DPRINT1("Failed to initialize the handles table\n");
516 ConSrvDeleteConsole(Console
);
517 ProcessData
->ConsoleHandle
= NULL
;
521 /* Duplicate the Input Event */
522 Status
= NtDuplicateObject(NtCurrentProcess(),
523 Console
->InputBuffer
.ActiveEvent
,
524 ProcessData
->Process
->ProcessHandle
,
525 &ProcessData
->InputWaitHandle
,
526 EVENT_ALL_ACCESS
, 0, 0);
527 if (!NT_SUCCESS(Status
))
529 DPRINT1("NtDuplicateObject() failed: %lu\n", Status
);
530 ConSrvFreeHandlesTable(ProcessData
);
531 ConSrvDeleteConsole(Console
);
532 ProcessData
->ConsoleHandle
= NULL
;
536 /* Insert the process into the processes list of the console */
537 InsertHeadList(&Console
->ProcessList
, &ProcessData
->ConsoleLink
);
539 /* Add a reference count because the process is tied to the console */
540 _InterlockedIncrement(&Console
->ReferenceCount
);
542 /* Update the internal info of the terminal */
543 TermRefreshInternalInfo(Console
);
545 return STATUS_SUCCESS
;
549 ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData
,
550 HANDLE ConsoleHandle
,
551 BOOL CreateNewHandlesTable
,
552 PHANDLE pInputHandle
,
553 PHANDLE pOutputHandle
,
554 PHANDLE pErrorHandle
)
556 NTSTATUS Status
= STATUS_SUCCESS
;
559 /* Validate and lock the console */
560 if (!ConSrvValidateConsole(&Console
,
562 CONSOLE_RUNNING
, TRUE
))
564 // FIXME: Find another status code
565 return STATUS_UNSUCCESSFUL
;
568 /* Inherit the console */
569 ProcessData
->ConsoleHandle
= ConsoleHandle
;
571 if (CreateNewHandlesTable
)
574 * We are about to create a new console. However when ConSrvNewProcess
575 * was called, we didn't know that we wanted to create a new console and
576 * therefore, we by default inherited the handles table from our parent
577 * process. It's only now that we notice that in fact we do not need
578 * them, because we've created a new console and thus we must use it.
580 * Therefore, free the handles table so that we can recreate
581 * a new one later on.
583 ConSrvFreeHandlesTable(ProcessData
);
585 /* Initialize the handles table */
586 Status
= ConSrvInitHandlesTable(ProcessData
,
591 if (!NT_SUCCESS(Status
))
593 DPRINT1("Failed to initialize the handles table\n");
594 ProcessData
->ConsoleHandle
= NULL
;
599 /* Duplicate the Input Event */
600 Status
= NtDuplicateObject(NtCurrentProcess(),
601 Console
->InputBuffer
.ActiveEvent
,
602 ProcessData
->Process
->ProcessHandle
,
603 &ProcessData
->InputWaitHandle
,
604 EVENT_ALL_ACCESS
, 0, 0);
605 if (!NT_SUCCESS(Status
))
607 DPRINT1("NtDuplicateObject() failed: %lu\n", Status
);
608 ConSrvFreeHandlesTable(ProcessData
); // NOTE: Always free the handles table.
609 ProcessData
->ConsoleHandle
= NULL
;
613 /* Insert the process into the processes list of the console */
614 InsertHeadList(&Console
->ProcessList
, &ProcessData
->ConsoleLink
);
616 /* Add a reference count because the process is tied to the console */
617 _InterlockedIncrement(&Console
->ReferenceCount
);
619 /* Update the internal info of the terminal */
620 TermRefreshInternalInfo(Console
);
622 Status
= STATUS_SUCCESS
;
625 /* Unlock the console and return */
626 LeaveCriticalSection(&Console
->Lock
);
631 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData
)
635 DPRINT("ConSrvRemoveConsole\n");
637 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
639 /* Validate and lock the console */
640 if (ConSrvValidateConsole(&Console
,
641 ProcessData
->ConsoleHandle
,
642 CONSOLE_RUNNING
, TRUE
))
644 /* Retrieve the console leader process */
645 PCONSOLE_PROCESS_DATA ConsoleLeaderProcess
= ConSrvGetConsoleLeaderProcess(Console
);
647 DPRINT("ConSrvRemoveConsole - Locking OK\n");
649 /* Close all console handles and free the handles table */
650 ConSrvFreeHandlesTable(ProcessData
);
652 /* Detach the process from the console */
653 ProcessData
->ConsoleHandle
= NULL
;
655 /* Remove the process from the console's list of processes */
656 RemoveEntryList(&ProcessData
->ConsoleLink
);
658 /* Check whether the console should send a last close notification */
659 if (Console
->NotifyLastClose
)
661 /* If we are removing the process which wants the last close notification... */
662 if (ProcessData
== Console
->NotifiedLastCloseProcess
)
664 /* ... just reset the flag and the pointer... */
665 Console
->NotifyLastClose
= FALSE
;
666 Console
->NotifiedLastCloseProcess
= NULL
;
669 * ... otherwise, if we are removing the console leader process
670 * (that cannot be the process wanting the notification, because
671 * the previous case already dealt with it)...
673 else if (ProcessData
== ConsoleLeaderProcess
)
676 * ... reset the flag first (so that we avoid multiple notifications)
677 * and then send the last close notification.
679 Console
->NotifyLastClose
= FALSE
;
680 ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT
, Console
->NotifiedLastCloseProcess
);
682 /* Only now, reset the pointer */
683 Console
->NotifiedLastCloseProcess
= NULL
;
687 /* Update the internal info of the terminal */
688 TermRefreshInternalInfo(Console
);
690 /* Release the console */
691 DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console
->ReferenceCount
);
692 ConSrvReleaseConsole(Console
, TRUE
);
693 //CloseHandle(ProcessData->InputWaitHandle);
694 //ProcessData->InputWaitHandle = NULL;
697 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
701 /* PUBLIC SERVER APIS *********************************************************/
703 CSR_API(SrvOpenConsole
)
706 * This API opens a handle to either the input buffer or to
707 * a screen-buffer of the console of the current process.
711 PCONSOLE_OPENCONSOLE OpenConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.OpenConsoleRequest
;
712 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
715 DWORD DesiredAccess
= OpenConsoleRequest
->DesiredAccess
;
716 DWORD ShareMode
= OpenConsoleRequest
->ShareMode
;
717 PCONSOLE_IO_OBJECT Object
;
719 OpenConsoleRequest
->Handle
= INVALID_HANDLE_VALUE
;
721 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
722 if (!NT_SUCCESS(Status
))
724 DPRINT1("Can't get console\n");
728 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
731 * Open a handle to either the active screen buffer or the input buffer.
733 if (OpenConsoleRequest
->HandleType
== HANDLE_OUTPUT
)
735 Object
= &Console
->ActiveBuffer
->Header
;
739 Object
= &Console
->InputBuffer
.Header
;
742 if (((DesiredAccess
& GENERIC_READ
) && Object
->ExclusiveRead
!= 0) ||
743 ((DesiredAccess
& GENERIC_WRITE
) && Object
->ExclusiveWrite
!= 0) ||
744 (!(ShareMode
& FILE_SHARE_READ
) && Object
->AccessRead
!= 0) ||
745 (!(ShareMode
& FILE_SHARE_WRITE
) && Object
->AccessWrite
!= 0))
747 DPRINT1("Sharing violation\n");
748 Status
= STATUS_SHARING_VIOLATION
;
752 Status
= ConSrvInsertObject(ProcessData
,
753 &OpenConsoleRequest
->Handle
,
756 OpenConsoleRequest
->InheritHandle
,
760 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
762 ConSrvReleaseConsole(Console
, TRUE
);
766 CSR_API(SrvDuplicateHandle
)
769 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.DuplicateHandleRequest
;
770 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
773 HANDLE SourceHandle
= DuplicateHandleRequest
->SourceHandle
;
774 ULONG Index
= HandleToULong(SourceHandle
) >> 2;
775 PCONSOLE_IO_HANDLE Entry
;
778 DuplicateHandleRequest
->TargetHandle
= INVALID_HANDLE_VALUE
;
780 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
781 if (!NT_SUCCESS(Status
))
783 DPRINT1("Can't get console\n");
787 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
789 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
790 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
792 if ( /** !IsConsoleHandle(SourceHandle) || **/
793 Index
>= ProcessData
->HandleTableSize
||
794 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
796 DPRINT1("Couldn't duplicate invalid handle 0x%p\n", SourceHandle
);
797 Status
= STATUS_INVALID_HANDLE
;
801 if (DuplicateHandleRequest
->Options
& DUPLICATE_SAME_ACCESS
)
803 DesiredAccess
= Entry
->Access
;
807 DesiredAccess
= DuplicateHandleRequest
->DesiredAccess
;
808 /* Make sure the source handle has all the desired flags */
809 if ((Entry
->Access
& DesiredAccess
) == 0)
811 DPRINT1("Handle 0x%p only has access %X; requested %X\n",
812 SourceHandle
, Entry
->Access
, DesiredAccess
);
813 Status
= STATUS_INVALID_PARAMETER
;
818 /* Insert the new handle inside the process handles table */
819 Status
= ConSrvInsertObject(ProcessData
,
820 &DuplicateHandleRequest
->TargetHandle
,
823 DuplicateHandleRequest
->InheritHandle
,
825 if (NT_SUCCESS(Status
) &&
826 (DuplicateHandleRequest
->Options
& DUPLICATE_CLOSE_SOURCE
))
828 /* Close the original handle if needed */
829 ConSrvCloseHandleEntry(Entry
);
833 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
835 ConSrvReleaseConsole(Console
, TRUE
);
839 CSR_API(SrvGetHandleInformation
)
842 PCONSOLE_GETHANDLEINFO GetHandleInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetHandleInfoRequest
;
843 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
846 HANDLE Handle
= GetHandleInfoRequest
->Handle
;
847 ULONG Index
= HandleToULong(Handle
) >> 2;
848 PCONSOLE_IO_HANDLE Entry
;
850 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
851 if (!NT_SUCCESS(Status
))
853 DPRINT1("Can't get console\n");
857 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
859 ASSERT(ProcessData
->HandleTable
);
860 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
861 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
863 if (!IsConsoleHandle(Handle
) ||
864 Index
>= ProcessData
->HandleTableSize
||
865 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
867 Status
= STATUS_INVALID_HANDLE
;
872 * Retrieve the handle information flags. The console server
873 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
875 GetHandleInfoRequest
->Flags
= 0;
876 if (Entry
->Inheritable
) GetHandleInfoRequest
->Flags
|= HANDLE_FLAG_INHERIT
;
878 Status
= STATUS_SUCCESS
;
881 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
883 ConSrvReleaseConsole(Console
, TRUE
);
887 CSR_API(SrvSetHandleInformation
)
890 PCONSOLE_SETHANDLEINFO SetHandleInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHandleInfoRequest
;
891 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
894 HANDLE Handle
= SetHandleInfoRequest
->Handle
;
895 ULONG Index
= HandleToULong(Handle
) >> 2;
896 PCONSOLE_IO_HANDLE Entry
;
898 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
899 if (!NT_SUCCESS(Status
))
901 DPRINT1("Can't get console\n");
905 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
907 ASSERT(ProcessData
->HandleTable
);
908 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
909 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
911 if (!IsConsoleHandle(Handle
) ||
912 Index
>= ProcessData
->HandleTableSize
||
913 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
915 Status
= STATUS_INVALID_HANDLE
;
920 * Modify the handle information flags. The console server
921 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
923 if (SetHandleInfoRequest
->Mask
& HANDLE_FLAG_INHERIT
)
925 Entry
->Inheritable
= ((SetHandleInfoRequest
->Flags
& HANDLE_FLAG_INHERIT
) != 0);
928 Status
= STATUS_SUCCESS
;
931 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
933 ConSrvReleaseConsole(Console
, TRUE
);
937 CSR_API(SrvCloseHandle
)
940 PCONSOLE_CLOSEHANDLE CloseHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.CloseHandleRequest
;
941 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
944 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
945 if (!NT_SUCCESS(Status
))
947 DPRINT1("Can't get console\n");
951 Status
= ConSrvRemoveObject(ProcessData
, CloseHandleRequest
->Handle
);
953 ConSrvReleaseConsole(Console
, TRUE
);
957 CSR_API(SrvVerifyConsoleIoHandle
)
960 PCONSOLE_VERIFYHANDLE VerifyHandleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.VerifyHandleRequest
;
961 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
964 HANDLE IoHandle
= VerifyHandleRequest
->Handle
;
965 ULONG Index
= HandleToULong(IoHandle
) >> 2;
967 VerifyHandleRequest
->IsValid
= FALSE
;
969 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
970 if (!NT_SUCCESS(Status
))
972 DPRINT1("Can't get console\n");
976 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
978 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
979 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
981 if (!IsConsoleHandle(IoHandle
) ||
982 Index
>= ProcessData
->HandleTableSize
||
983 ProcessData
->HandleTable
[Index
].Object
== NULL
)
985 DPRINT("SrvVerifyConsoleIoHandle failed\n");
989 VerifyHandleRequest
->IsValid
= TRUE
;
992 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
994 ConSrvReleaseConsole(Console
, TRUE
);
995 return STATUS_SUCCESS
;