X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=win32ss%2Fuser%2Fconsrv%2Fhandle.c;h=339dbb3646eec9d4a670237bed4e8a665ad7310b;hp=21acf942a925dbff70729bf6a41d6a9e4ffa69d6;hb=e2d2cb40e26869e432760765aee58eb4946ef640;hpb=e4d97e422fba34fdbc572071b57f345fc65d27a5 diff --git a/win32ss/user/consrv/handle.c b/win32ss/user/consrv/handle.c index 21acf942a92..339dbb3646e 100644 --- a/win32ss/user/consrv/handle.c +++ b/win32ss/user/consrv/handle.c @@ -2,7 +2,7 @@ * LICENSE: GPL - See COPYING in the top level directory * PROJECT: ReactOS Console Server DLL * FILE: win32ss/user/consrv/handle.c - * PURPOSE: Console IO Handle functions + * PURPOSE: Console I/O Handles functions * PROGRAMMERS: */ @@ -11,14 +11,14 @@ #include "consrv.h" #include "conio.h" -#define NDEBUG +//#define NDEBUG #include /* PRIVATE FUNCTIONS *********************************************************/ static INT -AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change) +AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry, INT Change) { Object_t *Object = Entry->Object; @@ -35,42 +35,47 @@ AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change) } static VOID -Win32CsrCreateHandleEntry(PCSRSS_HANDLE Entry) +ConSrvCreateHandleEntry(PCONSOLE_IO_HANDLE Entry) { - Object_t *Object = Entry->Object; - EnterCriticalSection(&Object->Console->Lock); + /// LOCK /// Object_t *Object = Entry->Object; + /// LOCK /// EnterCriticalSection(&Object->Console->Lock); AdjustHandleCounts(Entry, +1); - LeaveCriticalSection(&Object->Console->Lock); + /// LOCK /// LeaveCriticalSection(&Object->Console->Lock); } static VOID -Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry) +ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry) { Object_t *Object = Entry->Object; - if (Object != NULL) { - PCSRSS_CONSOLE Console = Object->Console; - EnterCriticalSection(&Console->Lock); + /// LOCK /// PCONSOLE Console = Object->Console; + /// LOCK /// EnterCriticalSection(&Console->Lock); - if (Object->Type == CONIO_CONSOLE_MAGIC) + /* + * If this is a input handle, notify and dereference + * all the waits related to this handle. + */ + if (Object->Type == CONIO_INPUT_BUFFER_MAGIC) { - // LIST_ENTRY WaitQueue; + PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object; /* - * Wake-up all of the writing waiters if any, dereference them - * and purge them all from the list. + * Wake up all the writing waiters related to this handle for this + * input buffer, if any, then dereference them and purge them all + * from the list. + * To select them amongst all the waiters for this input buffer, + * pass the handle pointer to the waiters, then they will check + * whether or not they are related to this handle and if so, they + * return. */ - CsrNotifyWait(&Console->ReadWaitQueue, - WaitAll, - NULL, - (PVOID)0xdeaddead); - // InitializeListHead(&WaitQueue); - - // CsrMoveSatisfiedWait(&WaitQueue, &Console->ReadWaitQueue); - if (!IsListEmpty(&Console->ReadWaitQueue /* &WaitQueue */)) + CsrNotifyWait(&InputBuffer->ReadWaitQueue, + WaitAll, + NULL, + (PVOID)Entry); + if (!IsListEmpty(&InputBuffer->ReadWaitQueue)) { - CsrDereferenceWait(&Console->ReadWaitQueue /* &WaitQueue */); + CsrDereferenceWait(&InputBuffer->ReadWaitQueue); } } @@ -79,21 +84,20 @@ Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry) { if (Object->Type == CONIO_SCREEN_BUFFER_MAGIC) { - PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER)Object; + PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; /* ...unless it's the only buffer left. Windows allows deletion * even of the last buffer, but having to deal with a lack of * any active buffer might be error-prone. */ if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink) ConioDeleteScreenBuffer(Buffer); } - else if (Object->Type == CONIO_CONSOLE_MAGIC) + else if (Object->Type == CONIO_INPUT_BUFFER_MAGIC) { - /* TODO: FIXME: Destroy here the console ?? */ - // ConioDeleteConsole(Console); + DPRINT1("Closing the input buffer\n"); } } - LeaveCriticalSection(&Console->Lock); + /// LOCK /// LeaveCriticalSection(&Console->Lock); Entry->Object = NULL; } } @@ -101,17 +105,174 @@ Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry) /* FUNCTIONS *****************************************************************/ +/* static */ NTSTATUS +FASTCALL +ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData, + OUT PHANDLE pInputHandle, + OUT PHANDLE pOutputHandle, + OUT PHANDLE pErrorHandle) +{ + NTSTATUS Status; + HANDLE InputHandle = INVALID_HANDLE_VALUE, + OutputHandle = INVALID_HANDLE_VALUE, + ErrorHandle = INVALID_HANDLE_VALUE; + + /* + * Initialize the handles table. Use temporary variables to store + * the handles values in such a way that, if we fail, we don't + * return to the caller invalid handle values. + * + * Insert the IO handles. + */ + + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + + /* Insert the Input handle */ + Status = ConSrvInsertObject(ProcessData, + &InputHandle, + &ProcessData->Console->InputBuffer.Header, + GENERIC_READ | GENERIC_WRITE, + TRUE, + FILE_SHARE_READ | FILE_SHARE_WRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to insert the input handle\n"); + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + ConSrvFreeHandlesTable(ProcessData); + return Status; + } + + /* Insert the Output handle */ + Status = ConSrvInsertObject(ProcessData, + &OutputHandle, + &ProcessData->Console->ActiveBuffer->Header, + GENERIC_READ | GENERIC_WRITE, + TRUE, + FILE_SHARE_READ | FILE_SHARE_WRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to insert the output handle\n"); + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + ConSrvFreeHandlesTable(ProcessData); + return Status; + } + + /* Insert the Error handle */ + Status = ConSrvInsertObject(ProcessData, + &ErrorHandle, + &ProcessData->Console->ActiveBuffer->Header, + GENERIC_READ | GENERIC_WRITE, + TRUE, + FILE_SHARE_READ | FILE_SHARE_WRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to insert the error handle\n"); + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + ConSrvFreeHandlesTable(ProcessData); + return Status; + } + + /* Return the newly created handles */ + *pInputHandle = InputHandle; + *pOutputHandle = OutputHandle; + *pErrorHandle = ErrorHandle; + + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + return STATUS_SUCCESS; +} + NTSTATUS FASTCALL -Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData, - PHANDLE Handle, - Object_t *Object, - DWORD Access, - BOOL Inheritable, - DWORD ShareMode) +ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData, + IN PCONSOLE_PROCESS_DATA TargetProcessData) { + NTSTATUS Status = STATUS_SUCCESS; ULONG i; - PCSRSS_HANDLE Block; + + RtlEnterCriticalSection(&SourceProcessData->HandleTableLock); + + /* Inherit a handles table only if there is no already */ + if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */) + { + Status = STATUS_UNSUCCESSFUL; /* STATUS_INVALID_PARAMETER */ + goto Quit; + } + + /* Allocate a new handle table for the child process */ + TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap, + HEAP_ZERO_MEMORY, + SourceProcessData->HandleTableSize + * sizeof(CONSOLE_IO_HANDLE)); + if (TargetProcessData->HandleTable == NULL) + { + Status = STATUS_NO_MEMORY; + goto Quit; + } + + TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize; + + /* + * Parse the parent process' handles table and, for each handle, + * do a copy of it and reference it, if the handle is inheritable. + */ + for (i = 0; i < SourceProcessData->HandleTableSize; i++) + { + if (SourceProcessData->HandleTable[i].Object != NULL && + SourceProcessData->HandleTable[i].Inheritable) + { + /* + * Copy the handle data and increment the reference count of the + * pointed object (via the call to ConSrvCreateHandleEntry). + */ + TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i]; + ConSrvCreateHandleEntry(&TargetProcessData->HandleTable[i]); + } + } + +Quit: + RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock); + return Status; +} + +VOID +FASTCALL +ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData) +{ + DPRINT1("ConSrvFreeHandlesTable\n"); + + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + + if (ProcessData->HandleTable != NULL) + { + ULONG i; + + /* Close all console handles and free the handle table memory */ + for (i = 0; i < ProcessData->HandleTableSize; i++) + { + ConSrvCloseHandleEntry(&ProcessData->HandleTable[i]); + } + RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable); + ProcessData->HandleTable = NULL; + } + + ProcessData->HandleTableSize = 0; + + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); +} + +NTSTATUS +FASTCALL +ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData, + PHANDLE Handle, + Object_t *Object, + DWORD Access, + BOOL Inheritable, + DWORD ShareMode) +{ +#define IO_HANDLES_INCREMENT 2*3 + + ULONG i; + PCONSOLE_IO_HANDLE Block; RtlEnterCriticalSection(&ProcessData->HandleTableLock); @@ -126,7 +287,8 @@ Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData, { Block = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY, - (ProcessData->HandleTableSize + 64) * sizeof(CSRSS_HANDLE)); + (ProcessData->HandleTableSize + + IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE)); if (Block == NULL) { RtlLeaveCriticalSection(&ProcessData->HandleTableLock); @@ -134,25 +296,28 @@ Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData, } RtlCopyMemory(Block, ProcessData->HandleTable, - ProcessData->HandleTableSize * sizeof(CSRSS_HANDLE)); + ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE)); RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable); ProcessData->HandleTable = Block; - ProcessData->HandleTableSize += 64; + ProcessData->HandleTableSize += IO_HANDLES_INCREMENT; } + ProcessData->HandleTable[i].Object = Object; ProcessData->HandleTable[i].Access = Access; ProcessData->HandleTable[i].Inheritable = Inheritable; ProcessData->HandleTable[i].ShareMode = ShareMode; - Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]); - *Handle = UlongToHandle((i << 2) | 0x3); + ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]); + *Handle = ULongToHandle((i << 2) | 0x3); + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + return STATUS_SUCCESS; } NTSTATUS FASTCALL -Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData, - HANDLE Handle) +ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData, + HANDLE Handle) { ULONG_PTR h = (ULONG_PTR)Handle >> 2; Object_t *Object; @@ -165,7 +330,9 @@ Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData, RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_INVALID_HANDLE; } - Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]); + + DPRINT1("ConSrvRemoveObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]); + ConSrvCloseHandleEntry(&ProcessData->HandleTable[h]); RtlLeaveCriticalSection(&ProcessData->HandleTableLock); @@ -174,78 +341,248 @@ Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData, NTSTATUS FASTCALL -Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData, - HANDLE Handle, - Object_t **Object, - DWORD Access, - LONG Type) +ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData, + HANDLE Handle, + Object_t** Object, + PCONSOLE_IO_HANDLE* Entry OPTIONAL, + DWORD Access, + BOOL LockConsole, + ULONG Type) { ULONG_PTR h = (ULONG_PTR)Handle >> 2; + PCONSOLE_IO_HANDLE HandleEntry = NULL; + Object_t* ObjectEntry = NULL; - DPRINT("Win32CsrLockObject, Object: %x, %x, %x\n", - Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0); + ASSERT(Object); + if (Entry) *Entry = NULL; + + // DPRINT("ConSrvGetObject, Object: %x, %x, %x\n", + // Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0); RtlEnterCriticalSection(&ProcessData->HandleTableLock); - if ( !IsConsoleHandle(Handle) || - h >= ProcessData->HandleTableSize || - (*Object = ProcessData->HandleTable[h].Object) == NULL || - ~ProcessData->HandleTable[h].Access & Access || - (Type != 0 && (*Object)->Type != Type) ) + if ( IsConsoleHandle(Handle) && + h < ProcessData->HandleTableSize ) { - DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle); + HandleEntry = &ProcessData->HandleTable[h]; + ObjectEntry = HandleEntry->Object; + } + + if ( HandleEntry == NULL || + ObjectEntry == NULL || + (HandleEntry->Access & Access) == 0 || + (Type != 0 && ObjectEntry->Type != Type) ) + { + DPRINT1("ConSrvGetObject returning invalid handle (%x) of type %lu with access %lu\n", Handle, Type, Access); RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_INVALID_HANDLE; } - _InterlockedIncrement(&(*Object)->Console->ReferenceCount); + _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount); RtlLeaveCriticalSection(&ProcessData->HandleTableLock); - EnterCriticalSection(&((*Object)->Console->Lock)); + if (LockConsole) EnterCriticalSection(&ObjectEntry->Console->Lock); + + /* Return the objects to the caller */ + *Object = ObjectEntry; + if (Entry) *Entry = HandleEntry; + return STATUS_SUCCESS; } -VOID FASTCALL -Win32CsrUnlockConsole(PCSRSS_CONSOLE Console) +VOID +FASTCALL +ConSrvReleaseObject(Object_t *Object, + BOOL IsConsoleLocked) { - LeaveCriticalSection(&Console->Lock); + ConSrvReleaseConsole(Object->Console, IsConsoleLocked); +} -#if 0 - /* If it was the last held lock for the owning thread... */ - if (&Console->Lock.RecursionCount == 0) +NTSTATUS +FASTCALL +ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData, + LPCWSTR AppPath, + PHANDLE pInputHandle, + PHANDLE pOutputHandle, + PHANDLE pErrorHandle, + PCONSOLE_START_INFO ConsoleStartInfo) +{ + NTSTATUS Status = STATUS_SUCCESS; + + /* Initialize a new Console owned by this process */ + Status = ConSrvInitConsole(&ProcessData->Console, AppPath, ConsoleStartInfo, ProcessData->Process); + if (!NT_SUCCESS(Status)) { - /* ...dereference waiting threads if any */ - LIST_ENTRY WaitQueue; - InitializeListHead(&WaitQueue); + DPRINT1("Console initialization failed\n"); + return Status; + } - CsrMoveSatisfiedWait(&WaitQueue, Console->SatisfiedWaits); - Console->SatisfiedWaits = NULL; - if (!IsListEmpty(&WaitQueue)) + /* Initialize the handles table */ + Status = ConSrvInitHandlesTable(ProcessData, + pInputHandle, + pOutputHandle, + pErrorHandle); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to initialize the handles table\n"); + ConSrvDeleteConsole(ProcessData->Console); + ProcessData->Console = NULL; + return Status; + } + + /* Duplicate the Input Event */ + Status = NtDuplicateObject(NtCurrentProcess(), + ProcessData->Console->InputBuffer.ActiveEvent, + ProcessData->Process->ProcessHandle, + &ProcessData->ConsoleEvent, + EVENT_ALL_ACCESS, 0, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject() failed: %lu\n", Status); + ConSrvFreeHandlesTable(ProcessData); + ConSrvDeleteConsole(ProcessData->Console); + ProcessData->Console = NULL; + return Status; + } + + /* Insert the process into the processes list of the console */ + InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink); + + /* Add a reference count because the process is tied to the console */ + _InterlockedIncrement(&ProcessData->Console->ReferenceCount); + + return STATUS_SUCCESS; +} + +NTSTATUS +FASTCALL +ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData, + PCONSOLE Console, + BOOL CreateNewHandlesTable, + PHANDLE pInputHandle, + PHANDLE pOutputHandle, + PHANDLE pErrorHandle) +{ + NTSTATUS Status = STATUS_SUCCESS; + + /* Inherit the console */ + ProcessData->Console = Console; + + if (CreateNewHandlesTable) + { + /* Initialize the handles table */ + Status = ConSrvInitHandlesTable(ProcessData, + pInputHandle, + pOutputHandle, + pErrorHandle); + if (!NT_SUCCESS(Status)) { - CsrDereferenceWait(&WaitQueue); + DPRINT1("Failed to initialize the handles table\n"); + ProcessData->Console = NULL; + return Status; } } -#endif - /* Decrement reference count */ - if (_InterlockedDecrement(&Console->ReferenceCount) == 0) - ConioDeleteConsole(Console); + /* Duplicate the Input Event */ + Status = NtDuplicateObject(NtCurrentProcess(), + ProcessData->Console->InputBuffer.ActiveEvent, + ProcessData->Process->ProcessHandle, + &ProcessData->ConsoleEvent, + EVENT_ALL_ACCESS, 0, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject() failed: %lu\n", Status); + ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table. + ProcessData->Console = NULL; + return Status; + } + + /* Insert the process into the processes list of the console */ + InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink); + + /* Add a reference count because the process is tied to the console */ + _InterlockedIncrement(&ProcessData->Console->ReferenceCount); + + return STATUS_SUCCESS; } VOID FASTCALL -Win32CsrUnlockObject(Object_t *Object) +ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData) { - Win32CsrUnlockConsole(Object->Console); + PCONSOLE Console; + + DPRINT1("ConSrvRemoveConsole\n"); + + /* Close all console handles and free the handle table memory */ + ConSrvFreeHandlesTable(ProcessData); + + /* Detach process from console */ + Console = ProcessData->Console; + if (Console != NULL) + { + DPRINT1("ConSrvRemoveConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount); + ProcessData->Console = NULL; + + EnterCriticalSection(&Console->Lock); + DPRINT1("ConSrvRemoveConsole - Locking OK\n"); + + /* Remove ourselves from the console's list of processes */ + RemoveEntryList(&ProcessData->ConsoleLink); + + /* Update the console leader process */ + // SetConsoleWndConsoleLeaderCID(Console); + + /* Release the console */ + ConSrvReleaseConsole(Console, TRUE); + //CloseHandle(ProcessData->ConsoleEvent); + //ProcessData->ConsoleEvent = NULL; + } } +NTSTATUS +FASTCALL +ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData, + PCONSOLE* Console, + BOOL LockConsole) +{ + PCONSOLE ProcessConsole; + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + ProcessConsole = ProcessData->Console; + + if (!ProcessConsole) + { + *Console = NULL; + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + return STATUS_INVALID_HANDLE; + } + + InterlockedIncrement(&ProcessConsole->ReferenceCount); + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + + if (LockConsole) EnterCriticalSection(&ProcessConsole->Lock); + + *Console = ProcessConsole; + + return STATUS_SUCCESS; +} + +VOID FASTCALL +ConSrvReleaseConsole(PCONSOLE Console, + BOOL IsConsoleLocked) +{ + if (IsConsoleLocked) LeaveCriticalSection(&Console->Lock); + + /* Decrement reference count */ + if (_InterlockedDecrement(&Console->ReferenceCount) == 0) + ConSrvDeleteConsole(Console); +} -/** Remark: this function can be called by SrvAttachConsole (not yet implemented) **/ NTSTATUS NTAPI -ConsoleNewProcess(PCSR_PROCESS SourceProcess, - PCSR_PROCESS TargetProcess) +ConSrvNewProcess(PCSR_PROCESS SourceProcess, + PCSR_PROCESS TargetProcess) { /************************************************************************** * This function is called whenever a new process (GUI or CUI) is created. @@ -253,26 +590,18 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess, * Copy the parent's handles table here if both the parent and the child * processes are CUI. If we must actually create our proper console (and * thus do not inherit from the console handles of the parent's), then we - * will clean this table in the next ConsoleConnect call. Why we are doing + * will clean this table in the next ConSrvConnect call. Why we are doing * this? It's because here, we still don't know whether or not we must create * a new console instead of inherit it from the parent, and, because in - * ConsoleConnect we don't have any reference to the parent process anymore. + * ConSrvConnect we don't have any reference to the parent process anymore. **************************************************************************/ PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData; - ULONG i; - - DPRINT1("ConsoleNewProcess inside\n"); - DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess); /* An empty target process is invalid */ - if (!TargetProcess) - return STATUS_INVALID_PARAMETER; - - DPRINT1("ConsoleNewProcess - OK\n"); + if (!TargetProcess) return STATUS_INVALID_PARAMETER; TargetProcessData = ConsoleGetPerProcessData(TargetProcess); - DPRINT1("TargetProcessData = 0x%p\n", TargetProcessData); /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData)); @@ -280,22 +609,18 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess, TargetProcessData->Process = TargetProcess; TargetProcessData->ConsoleEvent = NULL; TargetProcessData->Console = TargetProcessData->ParentConsole = NULL; - // TargetProcessData->bInheritHandles = FALSE; TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE); // Testing TargetProcessData->HandleTableSize = 0; TargetProcessData->HandleTable = NULL; - /* HACK */ RtlZeroMemory(&TargetProcessData->HandleTableLock, sizeof(RTL_CRITICAL_SECTION)); RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock); /* Do nothing if the source process is NULL */ - if (!SourceProcess) - return STATUS_SUCCESS; + if (!SourceProcess) return STATUS_SUCCESS; SourceProcessData = ConsoleGetPerProcessData(SourceProcess); - DPRINT1("SourceProcessData = 0x%p\n", SourceProcessData); /* * If both of the processes (parent and new child) are console applications, @@ -304,68 +629,23 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess, if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */ TargetProcessData->ConsoleApp ) { -/* - if (TargetProcessData->HandleTableSize) - { - return STATUS_INVALID_PARAMETER; - } -*/ - - DPRINT1("ConsoleNewProcess - Copy the handle table (1)\n"); - /* Temporary "inherit" the console from the parent */ - TargetProcessData->ParentConsole = SourceProcessData->Console; - RtlEnterCriticalSection(&SourceProcessData->HandleTableLock); - DPRINT1("ConsoleNewProcess - Copy the handle table (2)\n"); - - /* Allocate a new handle table for the child process */ - TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap, - HEAP_ZERO_MEMORY, - SourceProcessData->HandleTableSize - * sizeof(CSRSS_HANDLE)); - if (TargetProcessData->HandleTable == NULL) - { - RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock); - return STATUS_UNSUCCESSFUL; - } + NTSTATUS Status; - TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize; + Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData); + if (!NT_SUCCESS(Status)) return Status; - /* - * Parse the parent process' handles table and, for each handle, - * do a copy of it and reference it, if the handle is inheritable. - */ - for (i = 0; i < SourceProcessData->HandleTableSize; i++) - { - if (SourceProcessData->HandleTable[i].Object != NULL && - SourceProcessData->HandleTable[i].Inheritable) - { - /* - * Copy the handle data and increment the reference count of the - * pointed object (via the call to Win32CsrCreateHandleEntry). - */ - TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i]; - Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]); - } - } - - RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock); - } - else - { - DPRINT1("ConsoleNewProcess - We don't launch a Console process : SourceProcessData->Console = 0x%p ; TargetProcess->Flags = %lu\n", SourceProcessData->Console, TargetProcess->Flags); + /* Temporary save the parent's console */ + TargetProcessData->ParentConsole = SourceProcessData->Console; } return STATUS_SUCCESS; } -// Temporary ; move it to a header. -NTSTATUS WINAPI CsrInitConsole(PCSRSS_CONSOLE* NewConsole, int ShowCmd); - NTSTATUS NTAPI -ConsoleConnect(IN PCSR_PROCESS CsrProcess, - IN OUT PVOID ConnectionInfo, - IN OUT PULONG ConnectionInfoLength) +ConSrvConnect(IN PCSR_PROCESS CsrProcess, + IN OUT PVOID ConnectionInfo, + IN OUT PULONG ConnectionInfoLength) { /************************************************************************** * This function is called whenever a CUI new process is created. @@ -374,10 +654,6 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, NTSTATUS Status = STATUS_SUCCESS; PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess); - BOOLEAN NewConsole = FALSE; - // PCSRSS_CONSOLE Console = NULL; - - DPRINT1("ConsoleConnect\n"); if ( ConnectionInfo == NULL || ConnectionInfoLength == NULL || @@ -390,222 +666,90 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, /* If we don't need a console, then get out of here */ if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps. { - DPRINT("ConsoleConnect - No console needed\n"); return STATUS_SUCCESS; } - RtlEnterCriticalSection(&ProcessData->HandleTableLock); - /* If we don't have a console, then create a new one... */ if (!ConnectInfo->Console || ConnectInfo->Console != ProcessData->ParentConsole) { - // PCSRSS_CONSOLE Console; - - DPRINT1("ConsoleConnect - Allocate a new console\n"); - - /* Initialize a new Console */ - NewConsole = TRUE; - Status = CsrInitConsole(&ProcessData->Console, ConnectInfo->ShowCmd); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Console initialization failed\n"); - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); - return Status; - } - } - else /* We inherit it from the parent */ - { - DPRINT1("ConsoleConnect - Reuse current (parent's) console\n"); - - /* Reuse our current console */ - NewConsole = FALSE; - ProcessData->Console = ConnectInfo->Console; - } - - /* Insert the process into the processes list of the console */ - InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink); - - /* Return it to the caller */ - ConnectInfo->Console = ProcessData->Console; - - /* Add a reference count because the process is tied to the console */ - _InterlockedIncrement(&ProcessData->Console->ReferenceCount); + DPRINT1("ConSrvConnect - Allocate a new console\n"); - if (NewConsole /* || !ProcessData->bInheritHandles */) - { /* - * We've just created a new console. However when ConsoleNewProcess was - * called, we didn't know that we wanted to create a new console and + * We are about to create a new console. However when ConSrvNewProcess + * was called, we didn't know that we wanted to create a new console and * therefore, we by default inherited the handles table from our parent * process. It's only now that we notice that in fact we do not need * them, because we've created a new console and thus we must use it. * - * Therefore, free our handles table and recreate a new one. - */ - - ULONG i; - - /* Close all console handles and free the handle table memory */ - for (i = 0; i < ProcessData->HandleTableSize; i++) - { - Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]); - } - ProcessData->HandleTableSize = 0; - RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable); - ProcessData->HandleTable = NULL; - - /* - * Create a new handle table - Insert the IO handles + * Therefore, free the console we can have and our handles table, + * and recreate a new one later on. */ - - /* Insert the Input handle */ - Status = Win32CsrInsertObject(ProcessData, - &ConnectInfo->InputHandle, - &ProcessData->Console->Header, - GENERIC_READ | GENERIC_WRITE, - TRUE, - FILE_SHARE_READ | FILE_SHARE_WRITE); + ConSrvRemoveConsole(ProcessData); + + /* Initialize a new Console owned by the Console Leader Process */ + Status = ConSrvAllocateConsole(ProcessData, + ConnectInfo->AppPath, + &ConnectInfo->InputHandle, + &ConnectInfo->OutputHandle, + &ConnectInfo->ErrorHandle, + &ConnectInfo->ConsoleStartInfo); if (!NT_SUCCESS(Status)) { - DPRINT1("Failed to insert the input handle\n"); - ConioDeleteConsole(ProcessData->Console); - ProcessData->Console = NULL; - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); - return Status; - } - - /* Insert the Output handle */ - Status = Win32CsrInsertObject(ProcessData, - &ConnectInfo->OutputHandle, - &ProcessData->Console->ActiveBuffer->Header, - GENERIC_READ | GENERIC_WRITE, - TRUE, - FILE_SHARE_READ | FILE_SHARE_WRITE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to insert the output handle\n"); - ConioDeleteConsole(ProcessData->Console); - Win32CsrReleaseObject(ProcessData, - ConnectInfo->InputHandle); - ProcessData->Console = NULL; - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + DPRINT1("Console allocation failed\n"); return Status; } + } + else /* We inherit it from the parent */ + { + DPRINT1("ConSrvConnect - Reuse current (parent's) console\n"); - /* Insert the Error handle */ - Status = Win32CsrInsertObject(ProcessData, - &ConnectInfo->ErrorHandle, - &ProcessData->Console->ActiveBuffer->Header, - GENERIC_READ | GENERIC_WRITE, - TRUE, - FILE_SHARE_READ | FILE_SHARE_WRITE); + /* Reuse our current console */ + Status = ConSrvInheritConsole(ProcessData, + ConnectInfo->Console, + FALSE, + NULL, // &ConnectInfo->InputHandle, + NULL, // &ConnectInfo->OutputHandle, + NULL); // &ConnectInfo->ErrorHandle); if (!NT_SUCCESS(Status)) { - DPRINT1("Failed to insert the error handle\n"); - ConioDeleteConsole(ProcessData->Console); - Win32CsrReleaseObject(ProcessData, - ConnectInfo->OutputHandle); - Win32CsrReleaseObject(ProcessData, - ConnectInfo->InputHandle); - ProcessData->Console = NULL; - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + DPRINT1("Console inheritance failed\n"); return Status; } } - /* Duplicate the Event */ - Status = NtDuplicateObject(NtCurrentProcess(), - ProcessData->Console->ActiveEvent, - ProcessData->Process->ProcessHandle, - &ProcessData->ConsoleEvent, - EVENT_ALL_ACCESS, 0, 0); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtDuplicateObject() failed: %lu\n", Status); - ConioDeleteConsole(ProcessData->Console); - if (NewConsole /* || !ProcessData->bInheritHandles */) - { - Win32CsrReleaseObject(ProcessData, - ConnectInfo->ErrorHandle); - Win32CsrReleaseObject(ProcessData, - ConnectInfo->OutputHandle); - Win32CsrReleaseObject(ProcessData, - ConnectInfo->InputHandle); - } - ProcessData->Console = NULL; - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); - return Status; - } + /* Return it to the caller */ + ConnectInfo->Console = ProcessData->Console; + /* Input Wait Handle */ ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent; + /* Set the Property Dialog Handler */ + ProcessData->PropDispatcher = ConnectInfo->PropDispatcher; + /* Set the Ctrl Dispatcher */ ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher; - DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher); - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_SUCCESS; } VOID -WINAPI -Win32CsrReleaseConsole(PCSR_PROCESS Process) -{ - PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process); - PCSRSS_CONSOLE Console; - ULONG i; - - DPRINT1("Win32CsrReleaseConsole\n"); - - RtlEnterCriticalSection(&ProcessData->HandleTableLock); - - /* Close all console handles and free the handle table memory */ - for (i = 0; i < ProcessData->HandleTableSize; i++) - { - Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]); - } - ProcessData->HandleTableSize = 0; - RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable); - ProcessData->HandleTable = NULL; - - /* Detach process from console */ - Console = ProcessData->Console; - if (Console != NULL) - { - DPRINT1("Win32CsrReleaseConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount); - ProcessData->Console = NULL; - EnterCriticalSection(&Console->Lock); - RemoveEntryList(&ProcessData->ConsoleLink); - Win32CsrUnlockConsole(Console); - //CloseHandle(ProcessData->ConsoleEvent); - //ProcessData->ConsoleEvent = NULL; - } - - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); -} - -VOID -WINAPI -ConsoleDisconnect(PCSR_PROCESS Process) +NTAPI +ConSrvDisconnect(PCSR_PROCESS Process) { PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process); /************************************************************************** * This function is called whenever a new process (GUI or CUI) is destroyed. - * - * Only do something if the process is a CUI. <-- modify this behaviour if - * we deal with a GUI which - * quits and acquired a - * console... **************************************************************************/ - DPRINT1("ConsoleDisconnect called\n"); - // if (ProcessData->Console != NULL) - if (ProcessData->ConsoleApp) + DPRINT1("ConSrvDisconnect\n"); + + if ( ProcessData->Console != NULL || + ProcessData->HandleTable != NULL ) { - DPRINT1("ConsoleDisconnect - calling Win32CsrReleaseConsole\n"); - Win32CsrReleaseConsole(Process); + DPRINT1("ConSrvDisconnect - calling ConSrvRemoveConsole\n"); + ConSrvRemoveConsole(ProcessData); } RtlDeleteCriticalSection(&ProcessData->HandleTableLock); @@ -615,27 +759,27 @@ ConsoleDisconnect(PCSR_PROCESS Process) CSR_API(SrvCloseHandle) { - PCSRSS_CLOSE_HANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest; + PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest; - return Win32CsrReleaseObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - CloseHandleRequest->Handle); + return ConSrvRemoveObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + CloseHandleRequest->ConsoleHandle); } CSR_API(SrvVerifyConsoleIoHandle) { NTSTATUS Status = STATUS_SUCCESS; - PCSRSS_VERIFY_HANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest; + PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); - HANDLE Handle = VerifyHandleRequest->Handle; - ULONG_PTR Index = (ULONG_PTR)Handle >> 2; + HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle; + ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2; RtlEnterCriticalSection(&ProcessData->HandleTableLock); - if (!IsConsoleHandle(Handle) || + if (!IsConsoleHandle(ConsoleHandle) || Index >= ProcessData->HandleTableSize || ProcessData->HandleTable[Index].Object == NULL) { - DPRINT("CsrVerifyObject failed\n"); + DPRINT("SrvVerifyConsoleIoHandle failed\n"); Status = STATUS_INVALID_HANDLE; } @@ -646,20 +790,20 @@ CSR_API(SrvVerifyConsoleIoHandle) CSR_API(SrvDuplicateHandle) { - PCSRSS_HANDLE Entry; + PCONSOLE_IO_HANDLE Entry; DWORD DesiredAccess; - PCSRSS_DUPLICATE_HANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest; + PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); - HANDLE Handle = DuplicateHandleRequest->Handle; - ULONG_PTR Index = (ULONG_PTR)Handle >> 2; + HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle; + ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2; RtlEnterCriticalSection(&ProcessData->HandleTableLock); - if ( /** !IsConsoleHandle(Handle) || **/ + if ( /** !IsConsoleHandle(ConsoleHandle) || **/ Index >= ProcessData->HandleTableSize || (Entry = &ProcessData->HandleTable[Index])->Object == NULL) { - DPRINT1("Couldn't duplicate invalid handle %p\n", Handle); + DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle); RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_INVALID_HANDLE; } @@ -672,41 +816,29 @@ CSR_API(SrvDuplicateHandle) { DesiredAccess = DuplicateHandleRequest->Access; /* Make sure the source handle has all the desired flags */ - if (~Entry->Access & DesiredAccess) + if ((Entry->Access & DesiredAccess) == 0) { DPRINT1("Handle %p only has access %X; requested %X\n", - Handle, Entry->Access, DesiredAccess); + ConsoleHandle, Entry->Access, DesiredAccess); RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_INVALID_PARAMETER; } } - ApiMessage->Status = Win32CsrInsertObject(ProcessData, - &DuplicateHandleRequest->Handle, // Use the new handle value! - Entry->Object, - DesiredAccess, - DuplicateHandleRequest->Inheritable, - Entry->ShareMode); + ApiMessage->Status = ConSrvInsertObject(ProcessData, + &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value! + Entry->Object, + DesiredAccess, + DuplicateHandleRequest->Inheritable, + Entry->ShareMode); if (NT_SUCCESS(ApiMessage->Status) && DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE) { - Win32CsrCloseHandleEntry(Entry); + ConSrvCloseHandleEntry(Entry); } RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return ApiMessage->Status; } -/** -CSR_API(CsrGetInputWaitHandle) -{ - PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle; - - GetConsoleInputWaitHandle->InputWaitHandle = - ConsoleGetPerProcessData(CsrGetClientThread()->Process)->ConsoleEvent; - - return STATUS_SUCCESS; -} -**/ - /* EOF */