diff --git a/AK/Types.h b/AK/Types.h index 9655c748dfe..15aa9432f1a 100644 --- a/AK/Types.h +++ b/AK/Types.h @@ -207,6 +207,17 @@ enum MemoryOrder { memory_order_seq_cst = __ATOMIC_SEQ_CST }; +#ifdef AK_OS_WINDOWS +inline void* to_handle(int fd) +{ + return reinterpret_cast(static_cast(fd)); +} +inline int to_fd(void* handle) +{ + return reinterpret_cast(handle); +} +#endif + } #if USING_AK_GLOBALLY @@ -216,4 +227,8 @@ using AK::explode_byte; using AK::MemoryOrder; using AK::nullptr_t; using AK::TriState; +# ifdef AK_OS_WINDOWS +using AK::to_fd; +using AK::to_handle; +# endif #endif diff --git a/Libraries/LibCore/AnonymousBufferWindows.cpp b/Libraries/LibCore/AnonymousBufferWindows.cpp index 0a0dfb58fc3..d13b5fe7431 100644 --- a/Libraries/LibCore/AnonymousBufferWindows.cpp +++ b/Libraries/LibCore/AnonymousBufferWindows.cpp @@ -1,12 +1,14 @@ /* * Copyright (c) 2021, Andreas Kling - * Copyright (c) 2024, stasoid + * Copyright (c) 2024-2025, stasoid * * SPDX-License-Identifier: BSD-2-Clause */ #include -#include +#include + +#include namespace Core { @@ -23,25 +25,25 @@ AnonymousBufferImpl::~AnonymousBufferImpl() VERIFY(UnmapViewOfFile(m_data)); if (m_fd != -1) - VERIFY(CloseHandle((HANDLE)(intptr_t)m_fd)); + MUST(System::close(m_fd)); } ErrorOr> AnonymousBufferImpl::create(size_t size) { - HANDLE map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, size >> 31 >> 1, size & 0xFFFFFFFF, NULL); + HANDLE map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, size >> 32, size & 0xFFFFFFFF, NULL); if (!map_handle) return Error::from_windows_error(); - return create((int)(intptr_t)map_handle, size); + return create(to_fd(map_handle), size); } ErrorOr> AnonymousBufferImpl::create(int fd, size_t size) { - void* ptr = MapViewOfFile((HANDLE)(intptr_t)fd, FILE_MAP_ALL_ACCESS, 0, 0, size); + void* ptr = MapViewOfFile(to_handle(fd), FILE_MAP_ALL_ACCESS, 0, 0, size); if (!ptr) return Error::from_windows_error(); - return adopt_nonnull_ref_or_enomem(new (nothrow) AnonymousBufferImpl(fd, size, ptr)); + return adopt_ref(*new AnonymousBufferImpl(fd, size, ptr)); } ErrorOr AnonymousBuffer::create_with_size(size_t size) diff --git a/Libraries/LibCore/EventLoopImplementationWindows.cpp b/Libraries/LibCore/EventLoopImplementationWindows.cpp index 27dfc0f1dfd..b10cb88e39b 100644 --- a/Libraries/LibCore/EventLoopImplementationWindows.cpp +++ b/Libraries/LibCore/EventLoopImplementationWindows.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Andreas Kling - * Copyright (c) 2024, stasoid + * Copyright (c) 2024-2025, stasoid * * SPDX-License-Identifier: BSD-2-Clause */ @@ -163,10 +163,8 @@ void EventLoopManagerWindows::register_notifier(Notifier& notifier) { HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); VERIFY(event); - SOCKET socket = _get_osfhandle(notifier.fd()); - VERIFY(socket != INVALID_SOCKET); - int rc = WSAEventSelect(socket, event, notifier_type_to_network_event(notifier.type())); - VERIFY(rc == 0); + int rc = WSAEventSelect(notifier.fd(), event, notifier_type_to_network_event(notifier.type())); + VERIFY(!rc); auto& notifiers = ThreadData::the().notifiers; VERIFY(!notifiers.get(event).has_value()); diff --git a/Libraries/LibCore/System.cpp b/Libraries/LibCore/System.cpp index 500e8eaec08..4d6d65f4dc6 100644 --- a/Libraries/LibCore/System.cpp +++ b/Libraries/LibCore/System.cpp @@ -1004,4 +1004,10 @@ int getpid() return ::getpid(); } +bool is_socket(int fd) +{ + auto result = fstat(fd); + return !result.is_error() && S_ISSOCK(result.value().st_mode); +} + } diff --git a/Libraries/LibCore/System.h b/Libraries/LibCore/System.h index 850e9324e8b..06b11979994 100644 --- a/Libraries/LibCore/System.h +++ b/Libraries/LibCore/System.h @@ -180,5 +180,6 @@ ErrorOr set_resource_limits(int resource, rlim_t limit); #endif int getpid(); +bool is_socket(int fd); } diff --git a/Libraries/LibCore/SystemWindows.cpp b/Libraries/LibCore/SystemWindows.cpp index 7b7deda69c6..519c236bfcf 100644 --- a/Libraries/LibCore/SystemWindows.cpp +++ b/Libraries/LibCore/SystemWindows.cpp @@ -12,72 +12,95 @@ #include #include #include -#include #include -#include #include +#include + namespace Core::System { -ErrorOr open(StringView path, int options, mode_t mode) +static void invalid_parameter_handler(wchar_t const*, wchar_t const*, wchar_t const*, unsigned int, uintptr_t) { - int fd = _open(ByteString(path).characters(), options | O_BINARY | _O_OBTAIN_DIR, mode); - if (fd < 0) - return Error::from_syscall("open"sv, -errno); - return fd; } -ErrorOr close(int fd) +static int init_crt_and_wsa() { - if (_close(fd) < 0) - return Error::from_syscall("close"sv, -errno); + WSADATA wsa; + WORD version = MAKEWORD(2, 2); + int rc = WSAStartup(version, &wsa); + VERIFY(!rc && wsa.wVersion == version); + + // Make _get_osfhandle return -1 instead of crashing on invalid fd in release (debug still __debugbreak's) + _set_invalid_parameter_handler(invalid_parameter_handler); + return 0; +} + +static auto dummy = init_crt_and_wsa(); + +ErrorOr open(StringView path, int options, mode_t mode) +{ + ByteString str = path; + int fd = _open(str.characters(), options | O_BINARY | _O_OBTAIN_DIR, mode); + if (fd < 0) + return Error::from_syscall("open"sv, -errno); + ScopeGuard guard = [&] { _close(fd); }; + return dup(_get_osfhandle(fd)); +} + +ErrorOr close(int handle) +{ + if (is_socket(handle)) { + if (closesocket(handle)) + return Error::from_windows_error(); + } else { + if (!CloseHandle(to_handle(handle))) + return Error::from_windows_error(); + } return {}; } -ErrorOr read(int fd, Bytes buffer) +ErrorOr read(int handle, Bytes buffer) { - int rc = _read(fd, buffer.data(), buffer.size()); - if (rc < 0) - return Error::from_syscall("read"sv, -errno); - return rc; + DWORD n_read = 0; + if (!ReadFile(to_handle(handle), buffer.data(), buffer.size(), &n_read, NULL)) + return Error::from_windows_error(); + return n_read; } -ErrorOr write(int fd, ReadonlyBytes buffer) +ErrorOr write(int handle, ReadonlyBytes buffer) { - int rc = _write(fd, buffer.data(), buffer.size()); - if (rc < 0) - return Error::from_syscall("write"sv, -errno); - return rc; + DWORD n_written = 0; + if (!WriteFile(to_handle(handle), buffer.data(), buffer.size(), &n_written, NULL)) + return Error::from_windows_error(); + return n_written; } -ErrorOr lseek(int fd, off_t offset, int whence) +ErrorOr lseek(int handle, off_t offset, int origin) { - long rc = _lseek(fd, offset, whence); - if (rc < 0) - return Error::from_syscall("lseek"sv, -errno); - return rc; + static_assert(FILE_BEGIN == SEEK_SET && FILE_CURRENT == SEEK_CUR && FILE_END == SEEK_END, "SetFilePointerEx origin values are incompatible with lseek"); + LARGE_INTEGER new_pointer = {}; + if (!SetFilePointerEx(to_handle(handle), { .QuadPart = offset }, &new_pointer, origin)) + return Error::from_windows_error(); + return new_pointer.QuadPart; } -ErrorOr ftruncate(int fd, off_t length) +ErrorOr ftruncate(int handle, off_t length) { - long position = _tell(fd); - if (position == -1) - return Error::from_errno(errno); + auto position = TRY(lseek(handle, 0, SEEK_CUR)); + ScopeGuard restore_position = [&] { MUST(lseek(handle, position, SEEK_SET)); }; - ScopeGuard restore_position { [&] { _lseek(fd, position, SEEK_SET); } }; + TRY(lseek(handle, length, SEEK_SET)); - auto result = lseek(fd, length, SEEK_SET); - if (result.is_error()) - return result.release_error(); - - if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) + if (!SetEndOfFile(to_handle(handle))) return Error::from_windows_error(); return {}; } -ErrorOr fstat(int fd) +ErrorOr fstat(int handle) { struct stat st = {}; + int fd = _open_osfhandle(TRY(dup(handle)), 0); + ScopeGuard guard = [&] { _close(fd); }; if (::fstat(fd, &st) < 0) return Error::from_syscall("fstat"sv, -errno); return st; @@ -154,10 +177,12 @@ ErrorOr fstatat(int, StringView, int) VERIFY_NOT_REACHED(); } -ErrorOr mmap(void* address, size_t size, int protection, int flags, int fd, off_t offset, size_t alignment, StringView) +ErrorOr mmap(void* address, size_t size, int protection, int flags, int file_handle, off_t offset, size_t alignment, StringView) { // custom alignment is not supported VERIFY(!alignment); + int fd = _open_osfhandle(TRY(dup(file_handle)), 0); + ScopeGuard guard = [&] { _close(fd); }; void* ptr = ::mmap(address, size, protection, flags, fd, offset); if (ptr == MAP_FAILED) return Error::from_syscall("mmap"sv, -errno); @@ -176,4 +201,28 @@ int getpid() return GetCurrentProcessId(); } +ErrorOr dup(int handle) +{ + if (is_socket(handle)) { + WSAPROTOCOL_INFO pi = {}; + if (WSADuplicateSocket(handle, GetCurrentProcessId(), &pi)) + return Error::from_windows_error(); + SOCKET socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, &pi, 0, WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT); + if (socket == INVALID_SOCKET) + return Error::from_windows_error(); + return socket; + } else { + HANDLE new_handle = 0; + if (!DuplicateHandle(GetCurrentProcess(), to_handle(handle), GetCurrentProcess(), &new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + return Error::from_windows_error(); + return to_fd(new_handle); + } +} + +bool is_socket(int handle) +{ + // FILE_TYPE_PIPE is returned for sockets and pipes. We don't use Windows pipes. + return GetFileType(to_handle(handle)) == FILE_TYPE_PIPE; +} + }