X-Git-Url: https://git.josue.xyz/?p=VSoRC%2F.git;a=blobdiff_plain;f=node_modules%2Fnode-pty%2Fsrc%2Fwin%2Fconpty.cc;fp=node_modules%2Fnode-pty%2Fsrc%2Fwin%2Fconpty.cc;h=0000000000000000000000000000000000000000;hp=4500f6ef0fc73eb1aa68a4af0d77402abaf69914;hb=5e96dd57ddd883604e87f62bdddcb111c63a6e1a;hpb=acb5f682a2b75b972710cabd81658f63071324b0 diff --git a/node_modules/node-pty/src/win/conpty.cc b/node_modules/node-pty/src/win/conpty.cc deleted file mode 100644 index 4500f6e..0000000 --- a/node_modules/node-pty/src/win/conpty.cc +++ /dev/null @@ -1,455 +0,0 @@ -/** - * Copyright (c) 2013-2015, Christopher Jeffrey, Peter Sunde (MIT License) - * Copyright (c) 2016, Daniel Imms (MIT License). - * Copyright (c) 2018, Microsoft Corporation (MIT License). - * - * pty.cc: - * This file is responsible for starting processes - * with pseudo-terminal file descriptors. - */ - -// node versions lower than 10 define this as 0x502 which disables many of the definitions needed to compile -#include -#if NODE_MODULE_VERSION <= 57 - #define _WIN32_WINNT 0x600 -#endif - -#include -#include -#include // PathCombine, PathIsRelative -#include -#include -#include -#include -#include -#include "path_util.h" - -extern "C" void init(v8::Local); - -// Taken from the RS5 Windows SDK, but redefined here in case we're targeting <= 17134 -#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE -#define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE \ - ProcThreadAttributeValue(22, FALSE, TRUE, FALSE) - -typedef VOID* HPCON; -typedef HRESULT (__stdcall *PFNCREATEPSEUDOCONSOLE)(COORD c, HANDLE hIn, HANDLE hOut, DWORD dwFlags, HPCON* phpcon); -typedef HRESULT (__stdcall *PFNRESIZEPSEUDOCONSOLE)(HPCON hpc, COORD newSize); -typedef void (__stdcall *PFNCLOSEPSEUDOCONSOLE)(HPCON hpc); - -#endif - -struct pty_baton { - int id; - HANDLE hIn; - HANDLE hOut; - HPCON hpc; - - HANDLE hShell; - HANDLE hWait; - Nan::Callback cb; - uv_async_t async; - uv_thread_t tid; - - pty_baton(int _id, HANDLE _hIn, HANDLE _hOut, HPCON _hpc) : id(_id), hIn(_hIn), hOut(_hOut), hpc(_hpc) {}; -}; - -static std::vector ptyHandles; -static volatile LONG ptyCounter; - -static pty_baton* get_pty_baton(int id) { - for (size_t i = 0; i < ptyHandles.size(); ++i) { - pty_baton* ptyHandle = ptyHandles[i]; - if (ptyHandle->id == id) { - return ptyHandle; - } - } - return nullptr; -} - -template -std::vector vectorFromString(const std::basic_string &str) { - return std::vector(str.begin(), str.end()); -} - -void throwNanError(const Nan::FunctionCallbackInfo* info, const char* text, const bool getLastError) { - std::stringstream errorText; - errorText << text; - if (getLastError) { - errorText << ", error code: " << GetLastError(); - } - Nan::ThrowError(errorText.str().c_str()); - (*info).GetReturnValue().SetUndefined(); -} - -// Returns a new server named pipe. It has not yet been connected. -bool createDataServerPipe(bool write, - std::wstring kind, - HANDLE* hServer, - std::wstring &name, - const std::wstring &pipeName) -{ - *hServer = INVALID_HANDLE_VALUE; - - name = L"\\\\.\\pipe\\" + pipeName + L"-" + kind; - - const DWORD winOpenMode = PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE/* | FILE_FLAG_OVERLAPPED */; - - SECURITY_ATTRIBUTES sa = {}; - sa.nLength = sizeof(sa); - - *hServer = CreateNamedPipeW( - name.c_str(), - /*dwOpenMode=*/winOpenMode, - /*dwPipeMode=*/PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - /*nMaxInstances=*/1, - /*nOutBufferSize=*/0, - /*nInBufferSize=*/0, - /*nDefaultTimeOut=*/30000, - &sa); - - return *hServer != INVALID_HANDLE_VALUE; -} - -HRESULT CreateNamedPipesAndPseudoConsole(COORD size, - DWORD dwFlags, - HANDLE *phInput, - HANDLE *phOutput, - HPCON* phPC, - std::wstring& inName, - std::wstring& outName, - const std::wstring& pipeName) -{ - HANDLE hLibrary = LoadLibraryExW(L"kernel32.dll", 0, 0); - bool fLoadedDll = hLibrary != nullptr; - if (fLoadedDll) - { - PFNCREATEPSEUDOCONSOLE const pfnCreate = (PFNCREATEPSEUDOCONSOLE)GetProcAddress((HMODULE)hLibrary, "CreatePseudoConsole"); - if (pfnCreate) - { - if (phPC == NULL || phInput == NULL || phOutput == NULL) - { - return E_INVALIDARG; - } - - bool success = createDataServerPipe(true, L"in", phInput, inName, pipeName); - if (!success) - { - return HRESULT_FROM_WIN32(GetLastError()); - } - success = createDataServerPipe(false, L"out", phOutput, outName, pipeName); - if (!success) - { - return HRESULT_FROM_WIN32(GetLastError()); - } - return pfnCreate(size, *phInput, *phOutput, dwFlags, phPC); - } - else - { - // Failed to find CreatePseudoConsole in kernel32. This is likely because - // the user is not running a build of Windows that supports that API. - // We should fall back to winpty in this case. - return HRESULT_FROM_WIN32(GetLastError()); - } - } - - // Failed to find kernel32. This is realy unlikely - honestly no idea how - // this is even possible to hit. But if it does happen, fall back to winpty. - return HRESULT_FROM_WIN32(GetLastError()); -} - -static NAN_METHOD(PtyStartProcess) { - Nan::HandleScope scope; - - v8::Local marshal; - std::wstring inName, outName; - BOOL fSuccess = FALSE; - std::unique_ptr mutableCommandline; - PROCESS_INFORMATION _piClient{}; - - if (info.Length() != 6 || - !info[0]->IsString() || - !info[1]->IsNumber() || - !info[2]->IsNumber() || - !info[3]->IsBoolean() || - !info[4]->IsString() || - !info[5]->IsBoolean()) { - Nan::ThrowError("Usage: pty.startProcess(file, cols, rows, debug, pipeName, inheritCursor)"); - return; - } - - const std::wstring filename(path_util::to_wstring(Nan::Utf8String(info[0]))); - const SHORT cols = info[1]->Uint32Value(Nan::GetCurrentContext()).FromJust(); - const SHORT rows = info[2]->Uint32Value(Nan::GetCurrentContext()).FromJust(); - const bool debug = Nan::To(info[3]).FromJust(); - const std::wstring pipeName(path_util::to_wstring(Nan::Utf8String(info[4]))); - const bool inheritCursor = Nan::To(info[5]).FromJust(); - - // use environment 'Path' variable to determine location of - // the relative path that we have recieved (e.g cmd.exe) - std::wstring shellpath; - if (::PathIsRelativeW(filename.c_str())) { - shellpath = path_util::get_shell_path(filename.c_str()); - } else { - shellpath = filename; - } - - std::string shellpath_(shellpath.begin(), shellpath.end()); - - if (shellpath.empty() || !path_util::file_exists(shellpath)) { - std::stringstream why; - why << "File not found: " << shellpath_; - Nan::ThrowError(why.str().c_str()); - return; - } - - HANDLE hIn, hOut; - HPCON hpc; - HRESULT hr = CreateNamedPipesAndPseudoConsole({cols, rows}, inheritCursor ? 1/*PSEUDOCONSOLE_INHERIT_CURSOR*/ : 0, &hIn, &hOut, &hpc, inName, outName, pipeName); - - // Restore default handling of ctrl+c - SetConsoleCtrlHandler(NULL, FALSE); - - // Set return values - marshal = Nan::New(); - - if (SUCCEEDED(hr)) { - // We were able to instantiate a conpty - const int ptyId = InterlockedIncrement(&ptyCounter); - Nan::Set(marshal, Nan::New("pty").ToLocalChecked(), Nan::New(ptyId)); - ptyHandles.insert(ptyHandles.end(), new pty_baton(ptyId, hIn, hOut, hpc)); - } else { - Nan::ThrowError("Cannot launch conpty"); - return; - } - - Nan::Set(marshal, Nan::New("fd").ToLocalChecked(), Nan::New(-1)); - { - std::string coninPipeNameStr(inName.begin(), inName.end()); - Nan::Set(marshal, Nan::New("conin").ToLocalChecked(), Nan::New(coninPipeNameStr).ToLocalChecked()); - - std::string conoutPipeNameStr(outName.begin(), outName.end()); - Nan::Set(marshal, Nan::New("conout").ToLocalChecked(), Nan::New(conoutPipeNameStr).ToLocalChecked()); - } - info.GetReturnValue().Set(marshal); -} - -VOID CALLBACK OnProcessExitWinEvent( - _In_ PVOID context, - _In_ BOOLEAN TimerOrWaitFired) { - pty_baton *baton = static_cast(context); - - // Fire OnProcessExit - uv_async_send(&baton->async); -} - -static void OnProcessExit(uv_async_t *async) { - Nan::HandleScope scope; - pty_baton *baton = static_cast(async->data); - - UnregisterWait(baton->hWait); - - // Get exit code - DWORD exitCode = 0; - GetExitCodeProcess(baton->hShell, &exitCode); - - // Call function - v8::Local args[1] = { - Nan::New(exitCode) - }; - - Nan::AsyncResource asyncResource("node-pty.callback"); - baton->cb.Call(1, args, &asyncResource); - // Clean up - baton->cb.Reset(); -} - -static NAN_METHOD(PtyConnect) { - Nan::HandleScope scope; - - // If we're working with conpty's we need to call ConnectNamedPipe here AFTER - // the Socket has attempted to connect to the other end, then actually - // spawn the process here. - - std::stringstream errorText; - BOOL fSuccess = FALSE; - - if (info.Length() != 5 || - !info[0]->IsNumber() || - !info[1]->IsString() || - !info[2]->IsString() || - !info[3]->IsArray() || - !info[4]->IsFunction()) { - Nan::ThrowError("Usage: pty.connect(id, cmdline, cwd, env, exitCallback)"); - return; - } - - const int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust(); - const std::wstring cmdline(path_util::to_wstring(Nan::Utf8String(info[1]))); - const std::wstring cwd(path_util::to_wstring(Nan::Utf8String(info[2]))); - const v8::Local envValues = info[3].As(); - const v8::Local exitCallback = v8::Local::Cast(info[4]); - - // Prepare command line - std::unique_ptr mutableCommandline = std::make_unique(cmdline.length() + 1); - HRESULT hr = StringCchCopyW(mutableCommandline.get(), cmdline.length() + 1, cmdline.c_str()); - - // Prepare cwd - std::unique_ptr mutableCwd = std::make_unique(cwd.length() + 1); - hr = StringCchCopyW(mutableCwd.get(), cwd.length() + 1, cwd.c_str()); - - // Prepare environment - std::wstring env; - if (!envValues.IsEmpty()) { - std::wstringstream envBlock; - for(uint32_t i = 0; i < envValues->Length(); i++) { - std::wstring envValue(path_util::to_wstring(Nan::Utf8String(Nan::Get(envValues, i).ToLocalChecked()))); - envBlock << envValue << L'\0'; - } - envBlock << L'\0'; - env = envBlock.str(); - } - auto envV = vectorFromString(env); - LPWSTR envArg = envV.empty() ? nullptr : envV.data(); - - // Fetch pty handle from ID and start process - pty_baton* handle = get_pty_baton(id); - - BOOL success = ConnectNamedPipe(handle->hIn, nullptr); - success = ConnectNamedPipe(handle->hOut, nullptr); - - // Attach the pseudoconsole to the client application we're creating - STARTUPINFOEXW siEx{0}; - siEx.StartupInfo.cb = sizeof(STARTUPINFOEXW); - siEx.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; - siEx.StartupInfo.hStdError = nullptr; - siEx.StartupInfo.hStdInput = nullptr; - siEx.StartupInfo.hStdOutput = nullptr; - - SIZE_T size = 0; - InitializeProcThreadAttributeList(NULL, 1, 0, &size); - BYTE *attrList = new BYTE[size]; - siEx.lpAttributeList = reinterpret_cast(attrList); - - fSuccess = InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size); - if (!fSuccess) { - return throwNanError(&info, "InitializeProcThreadAttributeList failed", true); - } - fSuccess = UpdateProcThreadAttribute(siEx.lpAttributeList, - 0, - PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, - handle->hpc, - sizeof(HPCON), - NULL, - NULL); - if (!fSuccess) { - return throwNanError(&info, "UpdateProcThreadAttribute failed", true); - } - - PROCESS_INFORMATION piClient{}; - fSuccess = !!CreateProcessW( - nullptr, - mutableCommandline.get(), - nullptr, // lpProcessAttributes - nullptr, // lpThreadAttributes - false, // bInheritHandles VERY IMPORTANT that this is false - EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags - envArg, // lpEnvironment - mutableCwd.get(), // lpCurrentDirectory - &siEx.StartupInfo, // lpStartupInfo - &piClient // lpProcessInformation - ); - if (!fSuccess) { - return throwNanError(&info, "Cannot create process", true); - } - - // Update handle - handle->hShell = piClient.hProcess; - handle->cb.Reset(exitCallback); - handle->async.data = handle; - - // Setup OnProcessExit callback - uv_async_init(uv_default_loop(), &handle->async, OnProcessExit); - - // Setup Windows wait for process exit event - RegisterWaitForSingleObject(&handle->hWait, piClient.hProcess, OnProcessExitWinEvent, (PVOID)handle, INFINITE, WT_EXECUTEONLYONCE); - - // Return - v8::Local marshal = Nan::New(); - Nan::Set(marshal, Nan::New("pid").ToLocalChecked(), Nan::New(piClient.dwProcessId)); - info.GetReturnValue().Set(marshal); -} - -static NAN_METHOD(PtyResize) { - Nan::HandleScope scope; - - if (info.Length() != 3 || - !info[0]->IsNumber() || - !info[1]->IsNumber() || - !info[2]->IsNumber()) { - Nan::ThrowError("Usage: pty.resize(id, cols, rows)"); - return; - } - - int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust(); - SHORT cols = info[1]->Uint32Value(Nan::GetCurrentContext()).FromJust(); - SHORT rows = info[2]->Uint32Value(Nan::GetCurrentContext()).FromJust(); - - const pty_baton* handle = get_pty_baton(id); - - HANDLE hLibrary = LoadLibraryExW(L"kernel32.dll", 0, 0); - bool fLoadedDll = hLibrary != nullptr; - if (fLoadedDll) - { - PFNRESIZEPSEUDOCONSOLE const pfnResizePseudoConsole = (PFNRESIZEPSEUDOCONSOLE)GetProcAddress((HMODULE)hLibrary, "ResizePseudoConsole"); - if (pfnResizePseudoConsole) - { - COORD size = {cols, rows}; - pfnResizePseudoConsole(handle->hpc, size); - } - } - - return info.GetReturnValue().SetUndefined(); -} - -static NAN_METHOD(PtyKill) { - Nan::HandleScope scope; - - if (info.Length() != 1 || - !info[0]->IsNumber()) { - Nan::ThrowError("Usage: pty.kill(id)"); - return; - } - - int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust(); - - const pty_baton* handle = get_pty_baton(id); - - HANDLE hLibrary = LoadLibraryExW(L"kernel32.dll", 0, 0); - bool fLoadedDll = hLibrary != nullptr; - if (fLoadedDll) - { - PFNCLOSEPSEUDOCONSOLE const pfnClosePseudoConsole = (PFNCLOSEPSEUDOCONSOLE)GetProcAddress((HMODULE)hLibrary, "ClosePseudoConsole"); - if (pfnClosePseudoConsole) - { - pfnClosePseudoConsole(handle->hpc); - } - } - - CloseHandle(handle->hShell); - - return info.GetReturnValue().SetUndefined(); -} - -/** -* Init -*/ - -extern "C" void init(v8::Local target) { - Nan::HandleScope scope; - Nan::SetMethod(target, "startProcess", PtyStartProcess); - Nan::SetMethod(target, "connect", PtyConnect); - Nan::SetMethod(target, "resize", PtyResize); - Nan::SetMethod(target, "kill", PtyKill); -}; - -NODE_MODULE(pty, init);