/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set sts=2 sw=2 et tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; /* exported LIBC, Win, createPipe, libc */ const LIBC = OS.Constants.libc; const Win = OS.Constants.Win; const LIBC_CHOICES = ["kernel32.dll"]; var win32 = { // On Windows 64, winapi_abi is an alias for default_abi. WINAPI: ctypes.winapi_abi, VOID: ctypes.void_t, BYTE: ctypes.uint8_t, WORD: ctypes.uint16_t, DWORD: ctypes.uint32_t, LONG: ctypes.long, LARGE_INTEGER: ctypes.int64_t, ULONGLONG: ctypes.uint64_t, UINT: ctypes.unsigned_int, UCHAR: ctypes.unsigned_char, BOOL: ctypes.bool, HANDLE: ctypes.voidptr_t, PVOID: ctypes.voidptr_t, LPVOID: ctypes.voidptr_t, CHAR: ctypes.char, WCHAR: ctypes.jschar, ULONG_PTR: ctypes.uintptr_t, SIZE_T: ctypes.size_t, PSIZE_T: ctypes.size_t.ptr, }; Object.assign(win32, { DWORD_PTR: win32.ULONG_PTR, LPSTR: win32.CHAR.ptr, LPWSTR: win32.WCHAR.ptr, LPBYTE: win32.BYTE.ptr, LPDWORD: win32.DWORD.ptr, LPHANDLE: win32.HANDLE.ptr, // This is an opaque type. PROC_THREAD_ATTRIBUTE_LIST: ctypes.char.array(), LPPROC_THREAD_ATTRIBUTE_LIST: ctypes.char.ptr, }); Object.assign(win32, { LPCSTR: win32.LPSTR, LPCWSTR: win32.LPWSTR, LPCVOID: win32.LPVOID, }); Object.assign(win32, { CREATE_SUSPENDED: 0x00000004, CREATE_NEW_CONSOLE: 0x00000010, CREATE_UNICODE_ENVIRONMENT: 0x00000400, CREATE_NO_WINDOW: 0x08000000, CREATE_BREAKAWAY_FROM_JOB: 0x01000000, EXTENDED_STARTUPINFO_PRESENT: 0x00080000, STARTF_USESTDHANDLES: 0x0100, DUPLICATE_CLOSE_SOURCE: 0x01, DUPLICATE_SAME_ACCESS: 0x02, ERROR_HANDLE_EOF: 38, ERROR_BROKEN_PIPE: 109, ERROR_INSUFFICIENT_BUFFER: 122, FILE_FLAG_OVERLAPPED: 0x40000000, PIPE_TYPE_BYTE: 0x00, PIPE_ACCESS_INBOUND: 0x01, PIPE_ACCESS_OUTBOUND: 0x02, PIPE_ACCESS_DUPLEX: 0x03, PIPE_WAIT: 0x00, PIPE_NOWAIT: 0x01, STILL_ACTIVE: 259, PROC_THREAD_ATTRIBUTE_HANDLE_LIST: 0x00020002, JobObjectBasicLimitInformation: 2, JobObjectExtendedLimitInformation: 9, JOB_OBJECT_LIMIT_BREAKAWAY_OK: 0x00000800, // These constants are 32-bit unsigned integers, but Windows defines // them as negative integers cast to an unsigned type. STD_INPUT_HANDLE: -10 + 0x100000000, STD_OUTPUT_HANDLE: -11 + 0x100000000, STD_ERROR_HANDLE: -12 + 0x100000000, WAIT_TIMEOUT: 0x00000102, WAIT_FAILED: 0xffffffff, }); Object.assign(win32, { JOBOBJECT_BASIC_LIMIT_INFORMATION: new ctypes.StructType("JOBOBJECT_BASIC_LIMIT_INFORMATION", [ {"PerProcessUserTimeLimit": win32.LARGE_INTEGER}, {"PerJobUserTimeLimit": win32.LARGE_INTEGER}, {"LimitFlags": win32.DWORD}, {"MinimumWorkingSetSize": win32.SIZE_T}, {"MaximumWorkingSetSize": win32.SIZE_T}, {"ActiveProcessLimit": win32.DWORD}, {"Affinity": win32.ULONG_PTR}, {"PriorityClass": win32.DWORD}, {"SchedulingClass": win32.DWORD}, ]), IO_COUNTERS: new ctypes.StructType("IO_COUNTERS", [ {"ReadOperationCount": win32.ULONGLONG}, {"WriteOperationCount": win32.ULONGLONG}, {"OtherOperationCount": win32.ULONGLONG}, {"ReadTransferCount": win32.ULONGLONG}, {"WriteTransferCount": win32.ULONGLONG}, {"OtherTransferCount": win32.ULONGLONG}, ]), }); Object.assign(win32, { JOBOBJECT_EXTENDED_LIMIT_INFORMATION: new ctypes.StructType("JOBOBJECT_EXTENDED_LIMIT_INFORMATION", [ {"BasicLimitInformation": win32.JOBOBJECT_BASIC_LIMIT_INFORMATION}, {"IoInfo": win32.IO_COUNTERS}, {"ProcessMemoryLimit": win32.SIZE_T}, {"JobMemoryLimit": win32.SIZE_T}, {"PeakProcessMemoryUsed": win32.SIZE_T}, {"PeakJobMemoryUsed": win32.SIZE_T}, ]), OVERLAPPED: new ctypes.StructType("OVERLAPPED", [ {"Internal": win32.ULONG_PTR}, {"InternalHigh": win32.ULONG_PTR}, {"Offset": win32.DWORD}, {"OffsetHigh": win32.DWORD}, {"hEvent": win32.HANDLE}, ]), PROCESS_INFORMATION: new ctypes.StructType("PROCESS_INFORMATION", [ {"hProcess": win32.HANDLE}, {"hThread": win32.HANDLE}, {"dwProcessId": win32.DWORD}, {"dwThreadId": win32.DWORD}, ]), SECURITY_ATTRIBUTES: new ctypes.StructType("SECURITY_ATTRIBUTES", [ {"nLength": win32.DWORD}, {"lpSecurityDescriptor": win32.LPVOID}, {"bInheritHandle": win32.BOOL}, ]), STARTUPINFOW: new ctypes.StructType("STARTUPINFOW", [ {"cb": win32.DWORD}, {"lpReserved": win32.LPWSTR}, {"lpDesktop": win32.LPWSTR}, {"lpTitle": win32.LPWSTR}, {"dwX": win32.DWORD}, {"dwY": win32.DWORD}, {"dwXSize": win32.DWORD}, {"dwYSize": win32.DWORD}, {"dwXCountChars": win32.DWORD}, {"dwYCountChars": win32.DWORD}, {"dwFillAttribute": win32.DWORD}, {"dwFlags": win32.DWORD}, {"wShowWindow": win32.WORD}, {"cbReserved2": win32.WORD}, {"lpReserved2": win32.LPBYTE}, {"hStdInput": win32.HANDLE}, {"hStdOutput": win32.HANDLE}, {"hStdError": win32.HANDLE}, ]), }); Object.assign(win32, { STARTUPINFOEXW: new ctypes.StructType("STARTUPINFOEXW", [ {"StartupInfo": win32.STARTUPINFOW}, {"lpAttributeList": win32.LPPROC_THREAD_ATTRIBUTE_LIST}, ]), }); var libc = new Library("libc", LIBC_CHOICES, { AssignProcessToJobObject: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hJob */ win32.HANDLE, /* hProcess */ ], CloseHandle: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hObject */ ], CreateEventW: [ win32.WINAPI, win32.HANDLE, win32.SECURITY_ATTRIBUTES.ptr, /* opt lpEventAttributes */ win32.BOOL, /* bManualReset */ win32.BOOL, /* bInitialState */ win32.LPWSTR, /* lpName */ ], CreateFileW: [ win32.WINAPI, win32.HANDLE, win32.LPWSTR, /* lpFileName */ win32.DWORD, /* dwDesiredAccess */ win32.DWORD, /* dwShareMode */ win32.SECURITY_ATTRIBUTES.ptr, /* opt lpSecurityAttributes */ win32.DWORD, /* dwCreationDisposition */ win32.DWORD, /* dwFlagsAndAttributes */ win32.HANDLE, /* opt hTemplateFile */ ], CreateJobObjectW: [ win32.WINAPI, win32.HANDLE, win32.SECURITY_ATTRIBUTES.ptr, /* opt lpJobAttributes */ win32.LPWSTR, /* lpName */ ], CreateNamedPipeW: [ win32.WINAPI, win32.HANDLE, win32.LPWSTR, /* lpName */ win32.DWORD, /* dwOpenMode */ win32.DWORD, /* dwPipeMode */ win32.DWORD, /* nMaxInstances */ win32.DWORD, /* nOutBufferSize */ win32.DWORD, /* nInBufferSize */ win32.DWORD, /* nDefaultTimeOut */ win32.SECURITY_ATTRIBUTES.ptr, /* opt lpSecurityAttributes */ ], CreatePipe: [ win32.WINAPI, win32.BOOL, win32.LPHANDLE, /* out hReadPipe */ win32.LPHANDLE, /* out hWritePipe */ win32.SECURITY_ATTRIBUTES.ptr, /* opt lpPipeAttributes */ win32.DWORD, /* nSize */ ], CreateProcessW: [ win32.WINAPI, win32.BOOL, win32.LPCWSTR, /* lpApplicationName */ win32.LPWSTR, /* lpCommandLine */ win32.SECURITY_ATTRIBUTES.ptr, /* lpProcessAttributes */ win32.SECURITY_ATTRIBUTES.ptr, /* lpThreadAttributes */ win32.BOOL, /* bInheritHandle */ win32.DWORD, /* dwCreationFlags */ win32.LPVOID, /* opt lpEnvironment */ win32.LPCWSTR, /* opt lpCurrentDirectory */ win32.STARTUPINFOW.ptr, /* lpStartupInfo */ win32.PROCESS_INFORMATION.ptr, /* out lpProcessInformation */ ], CreateSemaphoreW: [ win32.WINAPI, win32.HANDLE, win32.SECURITY_ATTRIBUTES.ptr, /* opt lpSemaphoreAttributes */ win32.LONG, /* lInitialCount */ win32.LONG, /* lMaximumCount */ win32.LPCWSTR, /* opt lpName */ ], DeleteProcThreadAttributeList: [ win32.WINAPI, win32.VOID, win32.LPPROC_THREAD_ATTRIBUTE_LIST, /* in/out lpAttributeList */ ], DuplicateHandle: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hSourceProcessHandle */ win32.HANDLE, /* hSourceHandle */ win32.HANDLE, /* hTargetProcessHandle */ win32.LPHANDLE, /* out lpTargetHandle */ win32.DWORD, /* dwDesiredAccess */ win32.BOOL, /* bInheritHandle */ win32.DWORD, /* dwOptions */ ], FreeEnvironmentStringsW: [ win32.WINAPI, win32.BOOL, win32.LPCWSTR, /* lpszEnvironmentBlock */ ], GetCurrentProcess: [ win32.WINAPI, win32.HANDLE, ], GetCurrentProcessId: [ win32.WINAPI, win32.DWORD, ], GetEnvironmentStringsW: [ win32.WINAPI, win32.LPCWSTR, ], GetExitCodeProcess: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hProcess */ win32.LPDWORD, /* lpExitCode */ ], GetOverlappedResult: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hFile */ win32.OVERLAPPED.ptr, /* lpOverlapped */ win32.LPDWORD, /* lpNumberOfBytesTransferred */ win32.BOOL, /* bWait */ ], GetStdHandle: [ win32.WINAPI, win32.HANDLE, win32.DWORD, /* nStdHandle */ ], InitializeProcThreadAttributeList: [ win32.WINAPI, win32.BOOL, win32.LPPROC_THREAD_ATTRIBUTE_LIST, /* out opt lpAttributeList */ win32.DWORD, /* dwAttributeCount */ win32.DWORD, /* dwFlags */ win32.PSIZE_T, /* in/out lpSize */ ], ReadFile: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hFile */ win32.LPVOID, /* out lpBuffer */ win32.DWORD, /* nNumberOfBytesToRead */ win32.LPDWORD, /* opt out lpNumberOfBytesRead */ win32.OVERLAPPED.ptr, /* opt in/out lpOverlapped */ ], ReleaseSemaphore: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hSemaphore */ win32.LONG, /* lReleaseCount */ win32.LONG.ptr, /* opt out lpPreviousCount */ ], ResumeThread: [ win32.WINAPI, win32.DWORD, win32.HANDLE, /* hThread */ ], SetInformationJobObject: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hJob */ ctypes.int, /* JobObjectInfoClass */ win32.LPVOID, /* lpJobObjectInfo */ win32.DWORD, /* cbJobObjectInfoLengt */ ], TerminateJobObject: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hJob */ win32.UINT, /* uExitCode */ ], TerminateProcess: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hProcess */ win32.UINT, /* uExitCode */ ], UpdateProcThreadAttribute: [ win32.WINAPI, win32.BOOL, win32.LPPROC_THREAD_ATTRIBUTE_LIST, /* in/out lpAttributeList */ win32.DWORD, /* dwFlags */ win32.DWORD_PTR, /* Attribute */ win32.PVOID, /* lpValue */ win32.SIZE_T, /* cbSize */ win32.PVOID, /* out opt lpPreviousValue */ win32.PSIZE_T, /* opt lpReturnSize */ ], WaitForMultipleObjects: [ win32.WINAPI, win32.DWORD, win32.DWORD, /* nCount */ win32.HANDLE.ptr, /* hHandles */ win32.BOOL, /* bWaitAll */ win32.DWORD, /* dwMilliseconds */ ], WaitForSingleObject: [ win32.WINAPI, win32.DWORD, win32.HANDLE, /* hHandle */ win32.BOOL, /* bWaitAll */ win32.DWORD, /* dwMilliseconds */ ], WriteFile: [ win32.WINAPI, win32.BOOL, win32.HANDLE, /* hFile */ win32.LPCVOID, /* lpBuffer */ win32.DWORD, /* nNumberOfBytesToRead */ win32.LPDWORD, /* opt out lpNumberOfBytesWritten */ win32.OVERLAPPED.ptr, /* opt in/out lpOverlapped */ ], }); let nextNamedPipeId = 0; win32.Handle = function(handle) { return ctypes.CDataFinalizer(win32.HANDLE(handle), libc.CloseHandle); }; win32.createPipe = function(secAttr, readFlags = 0, writeFlags = 0, size = 0) { readFlags |= win32.PIPE_ACCESS_INBOUND; writeFlags |= Win.FILE_ATTRIBUTE_NORMAL; if (size == 0) { size = 4096; } let pid = libc.GetCurrentProcessId(); let pipeName = String.raw`\\.\Pipe\SubProcessPipe.${pid}.${nextNamedPipeId++}`; let readHandle = libc.CreateNamedPipeW( pipeName, readFlags, win32.PIPE_TYPE_BYTE | win32.PIPE_WAIT, 1, /* number of connections */ size, /* output buffer size */ size, /* input buffer size */ 0, /* timeout */ secAttr.address()); let isInvalid = handle => String(handle) == String(win32.HANDLE(Win.INVALID_HANDLE_VALUE)); if (isInvalid(readHandle)) { return []; } let writeHandle = libc.CreateFileW( pipeName, Win.GENERIC_WRITE, 0, secAttr.address(), Win.OPEN_EXISTING, writeFlags, null); if (isInvalid(writeHandle)) { libc.CloseHandle(readHandle); return []; } return [win32.Handle(readHandle), win32.Handle(writeHandle)]; }; win32.createThreadAttributeList = function(handles) { try { void libc.InitializeProcThreadAttributeList; void libc.DeleteProcThreadAttributeList; void libc.UpdateProcThreadAttribute; } catch (e) { // This is only supported in Windows Vista and later. return null; } let size = win32.SIZE_T(); if (!libc.InitializeProcThreadAttributeList(null, 1, 0, size.address()) && ctypes.winLastError != win32.ERROR_INSUFFICIENT_BUFFER) { return null; } let attrList = win32.PROC_THREAD_ATTRIBUTE_LIST(size.value); if (!libc.InitializeProcThreadAttributeList(attrList, 1, 0, size.address())) { return null; } let ok = libc.UpdateProcThreadAttribute( attrList, 0, win32.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, handles.constructor.size, null, null); if (!ok) { libc.DeleteProcThreadAttributeList(attrList); return null; } return attrList; };