diff options
Diffstat (limited to 'toolkit/modules/subprocess/subprocess_shared_win.js')
-rw-r--r-- | toolkit/modules/subprocess/subprocess_shared_win.js | 538 |
1 files changed, 538 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 0000000000..2b9eb69c6d --- /dev/null +++ b/toolkit/modules/subprocess/subprocess_shared_win.js @@ -0,0 +1,538 @@ +/* -*- 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"; + +if (typeof Components !== "undefined") { + /* global OS */ + Cc["@mozilla.org/net/osfileconstantsservice;1"] + .getService(Ci.nsIOSFileConstantsService) + .init(); +} + +/* exported LIBC, Win, createPipe, libc, win32 */ + +// ctypes is either already available in the chrome worker scope, or defined +// in scope via loadSubScript. +/* global ctypes */ + +// This file is loaded into the same scope as subprocess_shared.js. +/* import-globals-from subprocess_shared.js */ + +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, { + INVALID_HANDLE_VALUE: ctypes.cast(ctypes.int64_t(-1), win32.HANDLE), + NULL_HANDLE_VALUE: ctypes.cast(ctypes.uintptr_t(0), win32.HANDLE), + + 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; +}; |