diff options
Diffstat (limited to 'toolkit/modules/subprocess/subprocess_shared_win.js')
-rw-r--r-- | toolkit/modules/subprocess/subprocess_shared_win.js | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/toolkit/modules/subprocess/subprocess_shared_win.js b/toolkit/modules/subprocess/subprocess_shared_win.js new file mode 100644 index 000000000..6267b8cc7 --- /dev/null +++ b/toolkit/modules/subprocess/subprocess_shared_win.js @@ -0,0 +1,522 @@ +/* -*- 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; +}; |