-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LibCore: Consistently treat file descriptors as handles on Windows
Also: * implement dup and is_socket * implement and call init_crt_and_wsa
- Loading branch information
Showing
5 changed files
with
97 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,14 @@ | ||
/* | ||
* Copyright (c) 2021, Andreas Kling <[email protected]> | ||
* Copyright (c) 2024, stasoid <[email protected]> | ||
* Copyright (c) 2024-2025, stasoid <[email protected]> | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
|
||
#include <LibCore/AnonymousBuffer.h> | ||
#include <windows.h> | ||
#include <LibCore/System.h> | ||
|
||
#include <AK/Windows.h> | ||
|
||
namespace Core { | ||
|
||
|
@@ -23,7 +25,7 @@ AnonymousBufferImpl::~AnonymousBufferImpl() | |
VERIFY(UnmapViewOfFile(m_data)); | ||
|
||
if (m_fd != -1) | ||
VERIFY(CloseHandle((HANDLE)(intptr_t)m_fd)); | ||
MUST(System::close(m_fd)); | ||
} | ||
|
||
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(size_t size) | ||
|
@@ -41,7 +43,7 @@ ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(int fd, | |
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> AnonymousBuffer::create_with_size(size_t size) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
/* | ||
* Copyright (c) 2023, Andreas Kling <[email protected]> | ||
* Copyright (c) 2024, stasoid <[email protected]> | ||
* Copyright (c) 2024-2025, stasoid <[email protected]> | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
|
@@ -180,10 +180,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()); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -180,5 +180,6 @@ ErrorOr<void> set_resource_limits(int resource, rlim_t limit); | |
#endif | ||
|
||
int getpid(); | ||
bool is_socket(int fd); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,80 +4,102 @@ | |
* Copyright (c) 2021-2022, Sam Atkins <[email protected]> | ||
* Copyright (c) 2022, Matthias Zimmerman <[email protected]> | ||
* Copyright (c) 2023, Cameron Youell <[email protected]> | ||
* Copyright (c) 2024, stasoid <[email protected]> | ||
* Copyright (c) 2024-2025, stasoid <[email protected]> | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
|
||
#include <AK/ByteString.h> | ||
#include <AK/ScopeGuard.h> | ||
#include <LibCore/System.h> | ||
#include <Windows.h> | ||
#include <direct.h> | ||
#include <io.h> | ||
#include <sys/mman.h> | ||
|
||
#include <AK/Windows.h> | ||
|
||
namespace Core::System { | ||
|
||
static void invalid_parameter_handler(wchar_t const*, wchar_t const*, wchar_t const*, unsigned int, uintptr_t) | ||
{ | ||
} | ||
|
||
static int init_crt_and_wsa() | ||
{ | ||
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<int> open(StringView path, int options, mode_t mode) | ||
{ | ||
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; | ||
ScopeGuard guard = [&] { _close(fd); }; | ||
return dup(_get_osfhandle(fd)); | ||
} | ||
|
||
ErrorOr<void> close(int fd) | ||
{ | ||
if (_close(fd) < 0) | ||
return Error::from_syscall("close"sv, -errno); | ||
if (is_socket(fd)) { | ||
if (closesocket(fd)) | ||
return Error::from_windows_error(); | ||
} else { | ||
if (!CloseHandle((HANDLE)(intptr_t)fd)) | ||
return Error::from_windows_error(); | ||
} | ||
return {}; | ||
} | ||
|
||
ErrorOr<ssize_t> read(int fd, Bytes buffer) | ||
ErrorOr<ssize_t> 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((HANDLE)(intptr_t)handle, buffer.data(), buffer.size(), &n_read, NULL)) | ||
return Error::from_windows_error(); | ||
return n_read; | ||
} | ||
|
||
ErrorOr<ssize_t> write(int fd, ReadonlyBytes buffer) | ||
ErrorOr<ssize_t> 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((HANDLE)(intptr_t)handle, buffer.data(), buffer.size(), &n_written, NULL)) | ||
return Error::from_windows_error(); | ||
return n_written; | ||
} | ||
|
||
ErrorOr<off_t> lseek(int fd, off_t offset, int whence) | ||
ErrorOr<off_t> 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((HANDLE)(intptr_t)handle, {.QuadPart = offset}, &new_pointer, origin)) | ||
return Error::from_windows_error(); | ||
return new_pointer.QuadPart; | ||
} | ||
|
||
ErrorOr<void> ftruncate(int fd, off_t length) | ||
ErrorOr<void> ftruncate(int handle, off_t length) | ||
{ | ||
long position = _tell(fd); | ||
if (position == -1) | ||
return Error::from_errno(errno); | ||
|
||
ScopeGuard restore_position { [&] { _lseek(fd, position, SEEK_SET); } }; | ||
auto position = TRY(lseek(handle, 0, SEEK_CUR)); | ||
ScopeGuard restore_position = [&] { MUST(lseek(handle, position, SEEK_SET)); }; | ||
|
||
auto result = lseek(fd, length, SEEK_SET); | ||
if (result.is_error()) | ||
return result.release_error(); | ||
TRY(lseek(handle, length, SEEK_SET)); | ||
|
||
if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) | ||
if (!SetEndOfFile((HANDLE)(intptr_t)handle)) | ||
return Error::from_windows_error(); | ||
return {}; | ||
} | ||
|
||
ErrorOr<struct stat> fstat(int fd) | ||
ErrorOr<struct stat> 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 +176,12 @@ ErrorOr<struct stat> fstatat(int, StringView, int) | |
VERIFY_NOT_REACHED(); | ||
} | ||
|
||
ErrorOr<void*> mmap(void* address, size_t size, int protection, int flags, int fd, off_t offset, size_t alignment, StringView) | ||
ErrorOr<void*> 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 +200,28 @@ int getpid() | |
return GetCurrentProcessId(); | ||
} | ||
|
||
ErrorOr<int> 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(), (HANDLE)(intptr_t)handle, GetCurrentProcess(), &new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) | ||
return Error::from_windows_error(); | ||
return (int)(intptr_t)new_handle; | ||
} | ||
} | ||
|
||
bool is_socket(int handle) | ||
{ | ||
// FILE_TYPE_PIPE is returned for sockets and pipes. We don't use Windows pipes. | ||
return GetFileType((HANDLE)(intptr_t)handle) == FILE_TYPE_PIPE; | ||
} | ||
|
||
} |