/* kernel32.cc: Win32 replacement functions. This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" #include "shared_info.h" #include "ntdll.h" #include "cygerrno.h" #include "security.h" #include "path.h" #include "fhandler.h" #include "dtable.h" #include "cygheap.h" #include "tls_pbuf.h" #include "winf.h" #include "sys/cygwin.h" /* Implement CreateEvent/OpenEvent so that named objects are always created in Cygwin shared object namespace. */ HANDLE CreateEventW (LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName) { HANDLE evt; UNICODE_STRING uname; OBJECT_ATTRIBUTES attr; NTSTATUS status; ULONG flags = 0; if (lpEventAttributes && lpEventAttributes->bInheritHandle) flags |= OBJ_INHERIT; if (lpName) { RtlInitUnicodeString (&uname, lpName); flags |= OBJ_OPENIF | OBJ_CASE_INSENSITIVE; } InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags, lpName ? get_shared_parent_dir () : NULL, lpEventAttributes ? lpEventAttributes->lpSecurityDescriptor : NULL); status = NtCreateEvent (&evt, EVENT_ALL_ACCESS, &attr, bManualReset ? NotificationEvent : SynchronizationEvent, bInitialState); if (!NT_SUCCESS (status)) { SetLastError (RtlNtStatusToDosError (status)); return NULL; } SetLastError (status == STATUS_OBJECT_NAME_EXISTS ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS); return evt; } HANDLE CreateEventA (LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName) { WCHAR name[MAX_PATH]; if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName)) { SetLastError (ERROR_FILENAME_EXCED_RANGE); return NULL; } return CreateEventW (lpEventAttributes, bManualReset, bInitialState, lpName ? name : NULL); } HANDLE OpenEventW (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName) { HANDLE evt; UNICODE_STRING uname; OBJECT_ATTRIBUTES attr; NTSTATUS status; ULONG flags = 0; if (bInheritHandle) flags |= OBJ_INHERIT; if (lpName) { RtlInitUnicodeString (&uname, lpName); flags |= OBJ_CASE_INSENSITIVE; } InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags, lpName ? get_shared_parent_dir () : NULL, NULL); status = NtOpenEvent (&evt, dwDesiredAccess, &attr); if (!NT_SUCCESS (status)) { SetLastError (RtlNtStatusToDosError (status)); return NULL; } return evt; } HANDLE OpenEventA (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName) { WCHAR name[MAX_PATH]; if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName)) { SetLastError (ERROR_FILENAME_EXCED_RANGE); return NULL; } return OpenEventW (dwDesiredAccess, bInheritHandle, lpName ? name : NULL); } /* Implement CreateMutex/OpenMutex so that named objects are always created in Cygwin shared object namespace. */ HANDLE CreateMutexW (LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName) { HANDLE mtx; UNICODE_STRING uname; OBJECT_ATTRIBUTES attr; NTSTATUS status; ULONG flags = 0; if (lpMutexAttributes && lpMutexAttributes->bInheritHandle) flags |= OBJ_INHERIT; if (lpName) { RtlInitUnicodeString (&uname, lpName); flags |= OBJ_OPENIF | OBJ_CASE_INSENSITIVE; } InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags, lpName ? get_shared_parent_dir () : NULL, lpMutexAttributes ? lpMutexAttributes->lpSecurityDescriptor : NULL); status = NtCreateMutant (&mtx, MUTEX_ALL_ACCESS, &attr, bInitialOwner); if (!NT_SUCCESS (status)) { SetLastError (RtlNtStatusToDosError (status)); return NULL; } SetLastError (status == STATUS_OBJECT_NAME_EXISTS ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS); return mtx; } HANDLE CreateMutexA (LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName) { WCHAR name[MAX_PATH]; if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName)) { SetLastError (ERROR_FILENAME_EXCED_RANGE); return NULL; } return CreateMutexW (lpMutexAttributes, bInitialOwner, lpName ? name : NULL); } HANDLE OpenMutexW (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName) { HANDLE mtx; UNICODE_STRING uname; OBJECT_ATTRIBUTES attr; NTSTATUS status; ULONG flags = 0; if (bInheritHandle) flags |= OBJ_INHERIT; if (lpName) { RtlInitUnicodeString (&uname, lpName); flags |= OBJ_CASE_INSENSITIVE; } InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags, lpName ? get_shared_parent_dir () : NULL, NULL); status = NtOpenMutant (&mtx, dwDesiredAccess, &attr); if (!NT_SUCCESS (status)) { SetLastError (RtlNtStatusToDosError (status)); return NULL; } return mtx; } HANDLE OpenMutexA (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName) { WCHAR name[MAX_PATH]; if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName)) { SetLastError (ERROR_FILENAME_EXCED_RANGE); return NULL; } return OpenMutexW (dwDesiredAccess, bInheritHandle, lpName ? name : NULL); } /* Implement CreateSemaphore/OpenSemaphore so that named objects are always created in Cygwin shared object namespace. */ HANDLE CreateSemaphoreW (LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName) { HANDLE sem; UNICODE_STRING uname; OBJECT_ATTRIBUTES attr; NTSTATUS status; ULONG flags = 0; if (lpSemaphoreAttributes && lpSemaphoreAttributes->bInheritHandle) flags |= OBJ_INHERIT; if (lpName) { RtlInitUnicodeString (&uname, lpName); flags |= OBJ_OPENIF | OBJ_CASE_INSENSITIVE; } InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags, lpName ? get_shared_parent_dir () : NULL, lpSemaphoreAttributes ? lpSemaphoreAttributes->lpSecurityDescriptor : NULL); status = NtCreateSemaphore (&sem, SEMAPHORE_ALL_ACCESS, &attr, lInitialCount, lMaximumCount); if (!NT_SUCCESS (status)) { SetLastError (RtlNtStatusToDosError (status)); return NULL; } SetLastError (status == STATUS_OBJECT_NAME_EXISTS ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS); return sem; } HANDLE CreateSemaphoreA (LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCSTR lpName) { WCHAR name[MAX_PATH]; if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName)) { SetLastError (ERROR_FILENAME_EXCED_RANGE); return NULL; } return CreateSemaphoreW (lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName ? name : NULL); } HANDLE OpenSemaphoreW (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName) { HANDLE sem; UNICODE_STRING uname; OBJECT_ATTRIBUTES attr; NTSTATUS status; ULONG flags = 0; if (bInheritHandle) flags |= OBJ_INHERIT; if (lpName) { RtlInitUnicodeString (&uname, lpName); flags |= OBJ_CASE_INSENSITIVE; } InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags, lpName ? get_shared_parent_dir () : NULL, NULL); status = NtOpenSemaphore (&sem, dwDesiredAccess, &attr); if (!NT_SUCCESS (status)) { SetLastError (RtlNtStatusToDosError (status)); return NULL; } return sem; } HANDLE OpenSemaphoreA (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName) { WCHAR name[MAX_PATH]; if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName)) { SetLastError (ERROR_FILENAME_EXCED_RANGE); return NULL; } return OpenSemaphoreW (dwDesiredAccess, bInheritHandle, lpName ? name : NULL); } /* Implement CreateFileMapping/OpenFileMapping so that named objects are always created in Cygwin shared object namespace. */ HANDLE CreateFileMappingW (HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName) { HANDLE sect; UNICODE_STRING uname; OBJECT_ATTRIBUTES attr; NTSTATUS status; ULONG flags = 0; ACCESS_MASK access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ; ULONG prot = flProtect & (PAGE_NOACCESS | PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); ULONG attribs = flProtect & (SEC_COMMIT | SEC_IMAGE | SEC_NOCACHE | SEC_RESERVE); LARGE_INTEGER size = {{ LowPart : dwMaximumSizeLow, HighPart : (LONG) dwMaximumSizeHigh }}; PLARGE_INTEGER psize = size.QuadPart ? &size : NULL; if (prot & (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) access |= SECTION_MAP_WRITE; if (prot & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) access |= SECTION_MAP_EXECUTE; if (lpAttributes && lpAttributes->bInheritHandle) flags |= OBJ_INHERIT; if (lpName) { RtlInitUnicodeString (&uname, lpName); flags |= OBJ_OPENIF | OBJ_CASE_INSENSITIVE; } InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags, lpName ? get_shared_parent_dir () : NULL, lpAttributes ? lpAttributes->lpSecurityDescriptor : NULL); if (!(attribs & (SEC_RESERVE | SEC_COMMIT))) attribs |= SEC_COMMIT; if (hFile == INVALID_HANDLE_VALUE) hFile = NULL; status = NtCreateSection (§, access, &attr, psize, prot, attribs, hFile); if (!NT_SUCCESS (status)) { SetLastError (RtlNtStatusToDosError (status)); return NULL; } SetLastError (status == STATUS_OBJECT_NAME_EXISTS ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS); return sect; } HANDLE CreateFileMappingA (HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName) { WCHAR name[MAX_PATH]; if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName)) { SetLastError (ERROR_FILENAME_EXCED_RANGE); return NULL; } return CreateFileMappingW (hFile, lpAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName ? name : NULL); } HANDLE OpenFileMappingW (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName) { HANDLE sect; UNICODE_STRING uname; OBJECT_ATTRIBUTES attr; NTSTATUS status; ULONG flags = 0; if (bInheritHandle) flags |= OBJ_INHERIT; if (lpName) { RtlInitUnicodeString (&uname, lpName); flags |= OBJ_CASE_INSENSITIVE; } InitializeObjectAttributes (&attr, lpName ? &uname : NULL, flags, lpName ? get_shared_parent_dir () : NULL, NULL); status = NtOpenSection (§, dwDesiredAccess, &attr); if (!NT_SUCCESS (status)) { SetLastError (RtlNtStatusToDosError (status)); return NULL; } return sect; } HANDLE OpenFileMappingA (DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName) { WCHAR name[MAX_PATH]; if (lpName && !sys_mbstowcs (name, MAX_PATH, lpName)) { SetLastError (ERROR_FILENAME_EXCED_RANGE); return NULL; } return OpenFileMappingW (dwDesiredAccess, bInheritHandle, lpName ? name : NULL); } /* The external functions below wrap Windows functions of the same name and provide a Windows interface to Cygwin functionality. */ /* Construct a unicode version of the Cygwin command line from __argv) */ static UNICODE_STRING * ucmd () { static UNICODE_STRING wcmd; tmp_pathbuf tp; if (!wcmd.Buffer) { linebuf cmd; char *win_progname = tp.c_get (); sys_wcstombs (win_progname, NT_MAX_PATH, global_progname); av newargv (__argc, __argv); if (newargv.argc) { cmd.fromargv (newargv, win_progname, true); RtlInitUnicodeString (&wcmd, cmd); } } return &wcmd; } /* Cygwin replacement for GetCommandLineW. Returns a concatenated wide string representing the argv list, constructed using roughly the same mechanism as child_info_spawn::worker */ extern "C" LPWSTR cygwin_GetCommandLineW (void) { return ucmd ()->Buffer; } /* Cygwin replacement for GetCommandLineA. Returns a concatenated string representing the argv list, constructed using roughly the same mechanism as child_info_spawn::worker */ extern "C" LPSTR cygwin_GetCommandLineA (void) { static ANSI_STRING cmd; if (!cmd.Buffer) RtlUnicodeStringToAnsiString (&cmd, ucmd (), TRUE); return cmd.Buffer; }