mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-23 21:15:14 +00:00
LibCore: Consistently treat file descriptors as handles on Windows
Also: * implement dup and is_socket * implement and call init_crt_and_wsa
This commit is contained in:
parent
6cf627be8a
commit
642b7b6a5e
6 changed files with 120 additions and 49 deletions
15
AK/Types.h
15
AK/Types.h
|
@ -207,6 +207,17 @@ enum MemoryOrder {
|
||||||
memory_order_seq_cst = __ATOMIC_SEQ_CST
|
memory_order_seq_cst = __ATOMIC_SEQ_CST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef AK_OS_WINDOWS
|
||||||
|
inline void* to_handle(int fd)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<void*>(static_cast<intptr_t>(fd));
|
||||||
|
}
|
||||||
|
inline int to_fd(void* handle)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<intptr_t>(handle);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USING_AK_GLOBALLY
|
#if USING_AK_GLOBALLY
|
||||||
|
@ -216,4 +227,8 @@ using AK::explode_byte;
|
||||||
using AK::MemoryOrder;
|
using AK::MemoryOrder;
|
||||||
using AK::nullptr_t;
|
using AK::nullptr_t;
|
||||||
using AK::TriState;
|
using AK::TriState;
|
||||||
|
# ifdef AK_OS_WINDOWS
|
||||||
|
using AK::to_fd;
|
||||||
|
using AK::to_handle;
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Andreas Kling <andreas@ladybird.org>
|
* Copyright (c) 2021, Andreas Kling <andreas@ladybird.org>
|
||||||
* Copyright (c) 2024, stasoid <stasoid@yahoo.com>
|
* Copyright (c) 2024-2025, stasoid <stasoid@yahoo.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibCore/AnonymousBuffer.h>
|
#include <LibCore/AnonymousBuffer.h>
|
||||||
#include <windows.h>
|
#include <LibCore/System.h>
|
||||||
|
|
||||||
|
#include <AK/Windows.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
@ -23,25 +25,25 @@ AnonymousBufferImpl::~AnonymousBufferImpl()
|
||||||
VERIFY(UnmapViewOfFile(m_data));
|
VERIFY(UnmapViewOfFile(m_data));
|
||||||
|
|
||||||
if (m_fd != -1)
|
if (m_fd != -1)
|
||||||
VERIFY(CloseHandle((HANDLE)(intptr_t)m_fd));
|
MUST(System::close(m_fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(size_t size)
|
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> 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)
|
if (!map_handle)
|
||||||
return Error::from_windows_error();
|
return Error::from_windows_error();
|
||||||
|
|
||||||
return create((int)(intptr_t)map_handle, size);
|
return create(to_fd(map_handle), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(int fd, size_t size)
|
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> 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)
|
if (!ptr)
|
||||||
return Error::from_windows_error();
|
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)
|
ErrorOr<AnonymousBuffer> AnonymousBuffer::create_with_size(size_t size)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Andreas Kling <andreas@ladybird.org>
|
* Copyright (c) 2023, Andreas Kling <andreas@ladybird.org>
|
||||||
* Copyright (c) 2024, stasoid <stasoid@yahoo.com>
|
* Copyright (c) 2024-2025, stasoid <stasoid@yahoo.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -163,10 +163,8 @@ void EventLoopManagerWindows::register_notifier(Notifier& notifier)
|
||||||
{
|
{
|
||||||
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
VERIFY(event);
|
VERIFY(event);
|
||||||
SOCKET socket = _get_osfhandle(notifier.fd());
|
int rc = WSAEventSelect(notifier.fd(), event, notifier_type_to_network_event(notifier.type()));
|
||||||
VERIFY(socket != INVALID_SOCKET);
|
VERIFY(!rc);
|
||||||
int rc = WSAEventSelect(socket, event, notifier_type_to_network_event(notifier.type()));
|
|
||||||
VERIFY(rc == 0);
|
|
||||||
|
|
||||||
auto& notifiers = ThreadData::the().notifiers;
|
auto& notifiers = ThreadData::the().notifiers;
|
||||||
VERIFY(!notifiers.get(event).has_value());
|
VERIFY(!notifiers.get(event).has_value());
|
||||||
|
|
|
@ -1004,4 +1004,10 @@ int getpid()
|
||||||
return ::getpid();
|
return ::getpid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_socket(int fd)
|
||||||
|
{
|
||||||
|
auto result = fstat(fd);
|
||||||
|
return !result.is_error() && S_ISSOCK(result.value().st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,5 +180,6 @@ ErrorOr<void> set_resource_limits(int resource, rlim_t limit);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int getpid();
|
int getpid();
|
||||||
|
bool is_socket(int fd);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,72 +12,95 @@
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/ScopeGuard.h>
|
#include <AK/ScopeGuard.h>
|
||||||
#include <LibCore/System.h>
|
#include <LibCore/System.h>
|
||||||
#include <Windows.h>
|
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <io.h>
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include <AK/Windows.h>
|
||||||
|
|
||||||
namespace Core::System {
|
namespace Core::System {
|
||||||
|
|
||||||
ErrorOr<int> 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<void> close(int fd)
|
static int init_crt_and_wsa()
|
||||||
{
|
{
|
||||||
if (_close(fd) < 0)
|
WSADATA wsa;
|
||||||
return Error::from_syscall("close"sv, -errno);
|
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)
|
||||||
|
{
|
||||||
|
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<void> 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 {};
|
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());
|
DWORD n_read = 0;
|
||||||
if (rc < 0)
|
if (!ReadFile(to_handle(handle), buffer.data(), buffer.size(), &n_read, NULL))
|
||||||
return Error::from_syscall("read"sv, -errno);
|
return Error::from_windows_error();
|
||||||
return rc;
|
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());
|
DWORD n_written = 0;
|
||||||
if (rc < 0)
|
if (!WriteFile(to_handle(handle), buffer.data(), buffer.size(), &n_written, NULL))
|
||||||
return Error::from_syscall("write"sv, -errno);
|
return Error::from_windows_error();
|
||||||
return rc;
|
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);
|
static_assert(FILE_BEGIN == SEEK_SET && FILE_CURRENT == SEEK_CUR && FILE_END == SEEK_END, "SetFilePointerEx origin values are incompatible with lseek");
|
||||||
if (rc < 0)
|
LARGE_INTEGER new_pointer = {};
|
||||||
return Error::from_syscall("lseek"sv, -errno);
|
if (!SetFilePointerEx(to_handle(handle), { .QuadPart = offset }, &new_pointer, origin))
|
||||||
return rc;
|
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);
|
auto position = TRY(lseek(handle, 0, SEEK_CUR));
|
||||||
if (position == -1)
|
ScopeGuard restore_position = [&] { MUST(lseek(handle, position, SEEK_SET)); };
|
||||||
return Error::from_errno(errno);
|
|
||||||
|
|
||||||
ScopeGuard restore_position { [&] { _lseek(fd, position, SEEK_SET); } };
|
TRY(lseek(handle, length, SEEK_SET));
|
||||||
|
|
||||||
auto result = lseek(fd, length, SEEK_SET);
|
if (!SetEndOfFile(to_handle(handle)))
|
||||||
if (result.is_error())
|
|
||||||
return result.release_error();
|
|
||||||
|
|
||||||
if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0)
|
|
||||||
return Error::from_windows_error();
|
return Error::from_windows_error();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<struct stat> fstat(int fd)
|
ErrorOr<struct stat> fstat(int handle)
|
||||||
{
|
{
|
||||||
struct stat st = {};
|
struct stat st = {};
|
||||||
|
int fd = _open_osfhandle(TRY(dup(handle)), 0);
|
||||||
|
ScopeGuard guard = [&] { _close(fd); };
|
||||||
if (::fstat(fd, &st) < 0)
|
if (::fstat(fd, &st) < 0)
|
||||||
return Error::from_syscall("fstat"sv, -errno);
|
return Error::from_syscall("fstat"sv, -errno);
|
||||||
return st;
|
return st;
|
||||||
|
@ -154,10 +177,12 @@ ErrorOr<struct stat> fstatat(int, StringView, int)
|
||||||
VERIFY_NOT_REACHED();
|
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
|
// custom alignment is not supported
|
||||||
VERIFY(!alignment);
|
VERIFY(!alignment);
|
||||||
|
int fd = _open_osfhandle(TRY(dup(file_handle)), 0);
|
||||||
|
ScopeGuard guard = [&] { _close(fd); };
|
||||||
void* ptr = ::mmap(address, size, protection, flags, fd, offset);
|
void* ptr = ::mmap(address, size, protection, flags, fd, offset);
|
||||||
if (ptr == MAP_FAILED)
|
if (ptr == MAP_FAILED)
|
||||||
return Error::from_syscall("mmap"sv, -errno);
|
return Error::from_syscall("mmap"sv, -errno);
|
||||||
|
@ -176,4 +201,28 @@ int getpid()
|
||||||
return GetCurrentProcessId();
|
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(), 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue