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 ********************************************************************/
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 PCONSRV_CONSOLE Console
= (PCONSRV_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.
120 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData
,
121 IN PCONSOLE_PROCESS_DATA TargetProcessData
)
123 NTSTATUS Status
= STATUS_SUCCESS
;
126 RtlEnterCriticalSection(&SourceProcessData
->HandleTableLock
);
128 /* Inherit a handles table only if there is no already */
129 if (TargetProcessData
->HandleTable
!= NULL
/* || TargetProcessData->HandleTableSize != 0 */)
131 Status
= STATUS_UNSUCCESSFUL
;
135 /* Allocate a new handle table for the child process */
136 TargetProcessData
->HandleTable
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
137 SourceProcessData
->HandleTableSize
138 * sizeof(CONSOLE_IO_HANDLE
));
139 if (TargetProcessData
->HandleTable
== NULL
)
141 Status
= STATUS_NO_MEMORY
;
145 TargetProcessData
->HandleTableSize
= SourceProcessData
->HandleTableSize
;
148 * Parse the parent process' handles table and, for each handle,
149 * do a copy of it and reference it, if the handle is inheritable.
151 for (i
= 0, j
= 0; i
< SourceProcessData
->HandleTableSize
; i
++)
153 if (SourceProcessData
->HandleTable
[i
].Object
!= NULL
&&
154 SourceProcessData
->HandleTable
[i
].Inheritable
)
157 * Copy the handle data and increment the reference count of the
158 * pointed object (via the call to ConSrvCreateHandleEntry == AdjustHandleCounts).
160 TargetProcessData
->HandleTable
[j
] = SourceProcessData
->HandleTable
[i
];
161 AdjustHandleCounts(&TargetProcessData
->HandleTable
[j
], +1);
167 RtlLeaveCriticalSection(&SourceProcessData
->HandleTableLock
);
172 ConSrvFreeHandlesTable(IN PCONSOLE_PROCESS_DATA ProcessData
)
174 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
176 if (ProcessData
->HandleTable
!= NULL
)
181 * ProcessData->ConsoleHandle is NULL (and the assertion fails) when
182 * ConSrvFreeHandlesTable is called in ConSrvConnect during the
183 * allocation of a new console.
185 // ASSERT(ProcessData->ConsoleHandle);
186 if (ProcessData
->ConsoleHandle
!= NULL
)
188 /* Close all the console handles */
189 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
191 ConSrvCloseHandle(&ProcessData
->HandleTable
[i
]);
194 /* Free the handles table memory */
195 ConsoleFreeHeap(ProcessData
->HandleTable
);
196 ProcessData
->HandleTable
= NULL
;
199 ProcessData
->HandleTableSize
= 0;
201 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
209 // ConSrvCreateObject
211 ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object
,
212 IN CONSOLE_IO_OBJECT_TYPE Type
,
216 // if (!Object) return;
219 Object
->Console
= Console
;
220 Object
->ReferenceCount
= 0;
222 Object
->AccessRead
= Object
->AccessWrite
= 0;
223 Object
->ExclusiveRead
= Object
->ExclusiveWrite
= 0;
227 ConSrvInsertObject(IN PCONSOLE_PROCESS_DATA ProcessData
,
229 IN PCONSOLE_IO_OBJECT Object
,
231 IN BOOLEAN Inheritable
,
234 #define IO_HANDLES_INCREMENT 2 * 3
237 PCONSOLE_IO_HANDLE Block
;
239 // NOTE: Commented out because calling code always lock HandleTableLock before.
240 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
242 ASSERT( (ProcessData
->HandleTable
== NULL
&& ProcessData
->HandleTableSize
== 0) ||
243 (ProcessData
->HandleTable
!= NULL
&& ProcessData
->HandleTableSize
!= 0) );
245 if (ProcessData
->HandleTable
)
247 for (i
= 0; i
< ProcessData
->HandleTableSize
; i
++)
249 if (ProcessData
->HandleTable
[i
].Object
== NULL
)
254 if (i
>= ProcessData
->HandleTableSize
)
256 /* Allocate a new handles table */
257 Block
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
258 (ProcessData
->HandleTableSize
+
259 IO_HANDLES_INCREMENT
) * sizeof(CONSOLE_IO_HANDLE
));
262 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
263 return STATUS_UNSUCCESSFUL
;
266 /* If we previously had a handles table, free it and use the new one */
267 if (ProcessData
->HandleTable
)
269 /* Copy the handles from the old table to the new one */
271 ProcessData
->HandleTable
,
272 ProcessData
->HandleTableSize
* sizeof(CONSOLE_IO_HANDLE
));
273 ConsoleFreeHeap(ProcessData
->HandleTable
);
275 ProcessData
->HandleTable
= Block
;
276 ProcessData
->HandleTableSize
+= IO_HANDLES_INCREMENT
;
279 ProcessData
->HandleTable
[i
].Object
= Object
;
280 ProcessData
->HandleTable
[i
].Access
= Access
;
281 ProcessData
->HandleTable
[i
].Inheritable
= Inheritable
;
282 ProcessData
->HandleTable
[i
].ShareMode
= ShareMode
;
283 AdjustHandleCounts(&ProcessData
->HandleTable
[i
], +1);
284 *Handle
= ULongToHandle((i
<< 2) | 0x3);
286 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
288 return STATUS_SUCCESS
;
292 ConSrvRemoveObject(IN PCONSOLE_PROCESS_DATA ProcessData
,
295 ULONG Index
= HandleToULong(Handle
) >> 2;
297 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
299 ASSERT(ProcessData
->HandleTable
);
300 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
301 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
303 if (Index
>= ProcessData
->HandleTableSize
||
304 ProcessData
->HandleTable
[Index
].Object
== NULL
)
306 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
307 return STATUS_INVALID_HANDLE
;
310 ASSERT(ProcessData
->ConsoleHandle
);
311 ConSrvCloseHandle(&ProcessData
->HandleTable
[Index
]);
313 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
314 return STATUS_SUCCESS
;
318 ConSrvGetObject(IN PCONSOLE_PROCESS_DATA ProcessData
,
320 OUT PCONSOLE_IO_OBJECT
* Object
,
321 OUT PVOID
* Entry OPTIONAL
,
323 IN BOOLEAN LockConsole
,
324 IN CONSOLE_IO_OBJECT_TYPE Type
)
327 ULONG Index
= HandleToULong(Handle
) >> 2;
328 PCONSOLE_IO_HANDLE HandleEntry
= NULL
;
329 PCONSOLE_IO_OBJECT ObjectEntry
= NULL
;
330 // PCONSRV_CONSOLE ObjectConsole;
333 if (Entry
) *Entry
= NULL
;
335 DPRINT("ConSrvGetObject -- Object: 0x%x, Handle: 0x%x\n", Object
, Handle
);
337 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
339 if ( IsConsoleHandle(Handle
) &&
340 Index
< ProcessData
->HandleTableSize
)
342 HandleEntry
= &ProcessData
->HandleTable
[Index
];
343 ObjectEntry
= HandleEntry
->Object
;
346 if ( HandleEntry
== NULL
||
347 ObjectEntry
== NULL
||
348 (HandleEntry
->Access
& Access
) == 0 ||
349 /*(Type != 0 && ObjectEntry->Type != Type)*/
350 (Type
!= 0 && (ObjectEntry
->Type
& Type
) == 0) )
352 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",
353 Handle
, Type
, Access
, ObjectEntry
, HandleEntry
, (ObjectEntry
? ObjectEntry
->Type
: 0), (HandleEntry
? HandleEntry
->Access
: 0));
355 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
356 return STATUS_INVALID_HANDLE
;
359 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
361 // Status = ConSrvGetConsole(ProcessData, &ObjectConsole, LockConsole);
362 // if (NT_SUCCESS(Status))
363 if (ConDrvValidateConsoleUnsafe(ObjectEntry
->Console
, CONSOLE_RUNNING
, LockConsole
))
365 _InterlockedIncrement(&ObjectEntry
->Console
->ReferenceCount
);
367 /* Return the objects to the caller */
368 *Object
= ObjectEntry
;
369 if (Entry
) *Entry
= HandleEntry
;
371 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
372 return STATUS_SUCCESS
;
376 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
377 return STATUS_INVALID_HANDLE
;
382 ConSrvReleaseObject(IN PCONSOLE_IO_OBJECT Object
,
383 IN BOOLEAN IsConsoleLocked
)
385 PCONSRV_CONSOLE ObjectConsole
= (PCONSRV_CONSOLE
)Object
->Console
;
386 ConSrvReleaseConsole(ObjectConsole
, IsConsoleLocked
);
390 /* PUBLIC SERVER APIS *********************************************************/
392 /* API_NUMBER: ConsolepOpenConsole */
393 CON_API(SrvOpenConsole
,
394 CONSOLE_OPENCONSOLE
, OpenConsoleRequest
)
397 * This API opens a handle to either the input buffer or to
398 * a screen-buffer of the console of the current process.
402 DWORD DesiredAccess
= OpenConsoleRequest
->DesiredAccess
;
403 DWORD ShareMode
= OpenConsoleRequest
->ShareMode
;
404 PCONSOLE_IO_OBJECT Object
;
406 OpenConsoleRequest
->Handle
= INVALID_HANDLE_VALUE
;
408 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
411 * Open a handle to either the active screen buffer or the input buffer.
413 if (OpenConsoleRequest
->HandleType
== HANDLE_OUTPUT
)
415 Object
= &Console
->ActiveBuffer
->Header
;
419 Object
= &Console
->InputBuffer
.Header
;
422 if (((DesiredAccess
& GENERIC_READ
) && Object
->ExclusiveRead
!= 0) ||
423 ((DesiredAccess
& GENERIC_WRITE
) && Object
->ExclusiveWrite
!= 0) ||
424 (!(ShareMode
& FILE_SHARE_READ
) && Object
->AccessRead
!= 0) ||
425 (!(ShareMode
& FILE_SHARE_WRITE
) && Object
->AccessWrite
!= 0))
427 DPRINT1("Sharing violation\n");
428 Status
= STATUS_SHARING_VIOLATION
;
432 Status
= ConSrvInsertObject(ProcessData
,
433 &OpenConsoleRequest
->Handle
,
436 OpenConsoleRequest
->InheritHandle
,
440 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
445 /* API_NUMBER: ConsolepDuplicateHandle */
446 CON_API(SrvDuplicateHandle
,
447 CONSOLE_DUPLICATEHANDLE
, DuplicateHandleRequest
)
450 HANDLE SourceHandle
= DuplicateHandleRequest
->SourceHandle
;
451 ULONG Index
= HandleToULong(SourceHandle
) >> 2;
452 PCONSOLE_IO_HANDLE Entry
;
455 DuplicateHandleRequest
->TargetHandle
= INVALID_HANDLE_VALUE
;
457 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
459 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
460 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
462 if ( /** !IsConsoleHandle(SourceHandle) || **/
463 Index
>= ProcessData
->HandleTableSize
||
464 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
466 DPRINT1("Couldn't duplicate invalid handle 0x%p\n", SourceHandle
);
467 Status
= STATUS_INVALID_HANDLE
;
471 if (DuplicateHandleRequest
->Options
& DUPLICATE_SAME_ACCESS
)
473 DesiredAccess
= Entry
->Access
;
477 DesiredAccess
= DuplicateHandleRequest
->DesiredAccess
;
478 /* Make sure the source handle has all the desired flags */
479 if ((Entry
->Access
& DesiredAccess
) == 0)
481 DPRINT1("Handle 0x%p only has access %X; requested %X\n",
482 SourceHandle
, Entry
->Access
, DesiredAccess
);
483 Status
= STATUS_INVALID_PARAMETER
;
488 /* Insert the new handle inside the process handles table */
489 Status
= ConSrvInsertObject(ProcessData
,
490 &DuplicateHandleRequest
->TargetHandle
,
493 DuplicateHandleRequest
->InheritHandle
,
495 if (NT_SUCCESS(Status
) &&
496 (DuplicateHandleRequest
->Options
& DUPLICATE_CLOSE_SOURCE
))
498 /* Close the original handle if needed */
499 ConSrvCloseHandle(Entry
);
503 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
508 /* API_NUMBER: ConsolepGetHandleInformation */
509 CON_API(SrvGetHandleInformation
,
510 CONSOLE_GETHANDLEINFO
, GetHandleInfoRequest
)
513 HANDLE Handle
= GetHandleInfoRequest
->Handle
;
514 ULONG Index
= HandleToULong(Handle
) >> 2;
515 PCONSOLE_IO_HANDLE Entry
;
517 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
519 ASSERT(ProcessData
->HandleTable
);
520 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
521 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
523 if (!IsConsoleHandle(Handle
) ||
524 Index
>= ProcessData
->HandleTableSize
||
525 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
527 Status
= STATUS_INVALID_HANDLE
;
532 * Retrieve the handle information flags. The console server
533 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
535 GetHandleInfoRequest
->Flags
= 0;
536 if (Entry
->Inheritable
) GetHandleInfoRequest
->Flags
|= HANDLE_FLAG_INHERIT
;
538 Status
= STATUS_SUCCESS
;
541 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
546 /* API_NUMBER: ConsolepSetHandleInformation */
547 CON_API(SrvSetHandleInformation
,
548 CONSOLE_SETHANDLEINFO
, SetHandleInfoRequest
)
551 HANDLE Handle
= SetHandleInfoRequest
->Handle
;
552 ULONG Index
= HandleToULong(Handle
) >> 2;
553 PCONSOLE_IO_HANDLE Entry
;
555 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
557 ASSERT(ProcessData
->HandleTable
);
558 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
559 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
561 if (!IsConsoleHandle(Handle
) ||
562 Index
>= ProcessData
->HandleTableSize
||
563 (Entry
= &ProcessData
->HandleTable
[Index
])->Object
== NULL
)
565 Status
= STATUS_INVALID_HANDLE
;
570 * Modify the handle information flags. The console server
571 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
573 if (SetHandleInfoRequest
->Mask
& HANDLE_FLAG_INHERIT
)
575 Entry
->Inheritable
= ((SetHandleInfoRequest
->Flags
& HANDLE_FLAG_INHERIT
) != 0);
578 Status
= STATUS_SUCCESS
;
581 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
586 /* API_NUMBER: ConsolepCloseHandle */
587 CON_API(SrvCloseHandle
,
588 CONSOLE_CLOSEHANDLE
, CloseHandleRequest
)
590 return ConSrvRemoveObject(ProcessData
, CloseHandleRequest
->Handle
);
593 /* API_NUMBER: ConsolepVerifyIoHandle */
594 CON_API(SrvVerifyConsoleIoHandle
,
595 CONSOLE_VERIFYHANDLE
, VerifyHandleRequest
)
597 HANDLE IoHandle
= VerifyHandleRequest
->Handle
;
598 ULONG Index
= HandleToULong(IoHandle
) >> 2;
600 VerifyHandleRequest
->IsValid
= FALSE
;
602 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
604 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
605 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
607 if (!IsConsoleHandle(IoHandle
) ||
608 Index
>= ProcessData
->HandleTableSize
||
609 ProcessData
->HandleTable
[Index
].Object
== NULL
)
611 DPRINT("SrvVerifyConsoleIoHandle failed\n");
615 VerifyHandleRequest
->IsValid
= TRUE
;
618 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
620 return STATUS_SUCCESS
;