This commit is contained in:
stasoid 2025-01-02 11:40:21 +00:00 committed by GitHub
commit eb83f4a26f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 164 additions and 46 deletions

View file

@ -10,6 +10,7 @@
#ifdef AK_OS_WINDOWS
# include <AK/ByteString.h>
# include <AK/HashMap.h>
# include <stdio.h>
# include <windows.h>
#endif
@ -21,31 +22,39 @@ Error Error::from_string_view_or_print_error_and_return_errno(StringView string_
}
#ifdef AK_OS_WINDOWS
Error Error::from_windows_error(DWORD code)
Error Error::from_windows_error(int code)
{
static HashMap<DWORD, ByteString> windows_errors;
static HashMap<int, ByteString> windows_errors;
auto string = windows_errors.get(code);
if (string.has_value()) {
if (string.has_value())
return Error::from_string_view(string->view());
} else {
char* message = nullptr;
auto size = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&message,
0,
nullptr);
if (size == 0)
return Error::from_string_view_or_print_error_and_return_errno("Unknown error"sv, code);
char* message = 0;
auto size = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&message,
0,
NULL);
windows_errors.set(code, { message, size });
LocalFree(message);
return from_windows_error(code);
if (size == 0) {
static char buffer[128];
snprintf(buffer, _countof(buffer), "Error 0x%08lX while getting text of error 0x%08X", GetLastError(), code);
return Error::from_string_view({ buffer, _countof(buffer) });
}
windows_errors.set(code, { message, size });
LocalFree(message);
return from_windows_error(code);
}
// This can be used both for generic Windows errors and for winsock errors because WSAGetLastError is forwarded to GetLastError.
Error Error::from_windows_error()
{
return from_windows_error(GetLastError());
}
#endif

View file

@ -7,13 +7,8 @@
#pragma once
#include <AK/StringView.h>
#include <AK/Try.h>
#include <AK/Variant.h>
#include <errno.h>
#include <string.h>
#ifdef AK_OS_WINDOWS
typedef unsigned long DWORD;
#endif
namespace AK {
@ -29,7 +24,8 @@ public:
}
#ifdef AK_OS_WINDOWS
static Error from_windows_error(DWORD code);
static Error from_windows_error(int code);
static Error from_windows_error();
#endif
// NOTE: For calling this method from within kernel code, we will simply print

View file

@ -6,7 +6,9 @@
*/
#include <LibCore/AnonymousBuffer.h>
#include <windows.h>
#include <LibCore/System.h>
#include <AK/Windows.h>
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<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(size_t size)
{
HANDLE map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, size >> 31 >> 1, size & 0xFFFFFFFF, NULL);
if (!map_handle)
return Error::from_windows_error(GetLastError());
return Error::from_windows_error();
return create((int)(intptr_t)map_handle, size);
return create(handle_to_fd(map_handle, System::FileMappingHandle), 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(System::fd_to_handle(fd), FILE_MAP_ALL_ACCESS, 0, 0, size);
if (!ptr)
return Error::from_windows_error(GetLastError());
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)

View file

@ -7,9 +7,10 @@
#include <LibCore/EventLoopImplementationWindows.h>
#include <LibCore/Notifier.h>
#include <LibCore/System.h>
#include <LibCore/ThreadEventQueue.h>
#include <WinSock2.h>
#include <io.h>
#include <AK/Windows.h>
struct Handle {
HANDLE handle = NULL;
@ -180,7 +181,7 @@ void EventLoopManagerWindows::register_notifier(Notifier& notifier)
{
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
VERIFY(event);
SOCKET socket = _get_osfhandle(notifier.fd());
SOCKET socket = (SOCKET)System::fd_to_handle(notifier.fd());
VERIFY(socket != INVALID_SOCKET);
int rc = WSAEventSelect(socket, event, notifier_type_to_network_event(notifier.type()));
VERIFY(rc == 0);

View file

@ -71,7 +71,7 @@ ErrorOr<Process> Process::spawn(ProcessSpawnOptions const& options)
&process_info);
if (!result)
return Error::from_windows_error(GetLastError());
return Error::from_windows_error();
CloseHandle(process_info.hThread);
@ -108,7 +108,7 @@ ErrorOr<String> Process::get_name()
DWORD length = GetModuleFileNameW(NULL, path, MAX_PATH);
if (!length)
return Error::from_windows_error(GetLastError());
return Error::from_windows_error();
return String::from_utf16(Utf16View { { (u16*)path, length } });
}
@ -150,11 +150,11 @@ ErrorOr<int> Process::wait_for_termination()
{
auto result = WaitForSingleObject(m_handle, INFINITE);
if (result == WAIT_FAILED)
return Error::from_windows_error(GetLastError());
return Error::from_windows_error();
DWORD exit_code = 0;
if (!GetExitCodeProcess(m_handle, &exit_code))
return Error::from_windows_error(GetLastError());
return Error::from_windows_error();
return exit_code;
}

View file

@ -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);
}
}

View file

@ -52,6 +52,18 @@ using socklen_t = int;
namespace Core::System {
#ifdef AK_OS_WINDOWS
enum HandleType {
FileHandle,
DirectoryHandle,
SocketHandle,
FileMappingHandle
};
int handle_to_fd(intptr_t handle, HandleType);
int handle_to_fd(void* handle, HandleType);
void* fd_to_handle(int fd);
#endif
#if !defined(AK_OS_MACOS) && !defined(AK_OS_HAIKU)
ErrorOr<int> accept4(int sockfd, struct sockaddr*, socklen_t*, int flags);
#endif
@ -180,5 +192,6 @@ ErrorOr<void> set_resource_limits(int resource, rlim_t limit);
#endif
int getpid();
bool is_socket(int fd);
}

View file

@ -12,13 +12,58 @@
#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();
int handle_to_fd(HANDLE handle, HandleType type)
{
return handle_to_fd((intptr_t)handle, type);
}
int handle_to_fd(intptr_t handle, HandleType type)
{
if (type != SocketHandle && type != FileMappingHandle)
return _open_osfhandle(handle, 0);
// Special treatment for socket and file mapping handles because:
// * _open_osfhandle doesn't support file mapping handles
// * _close doesn't properly support socket handles (it calls CloseHandle instead of closesocket)
// Handle value is held in lower 31 bits, and sign bit is set to indicate this is not a regular fd.
VERIFY((handle >> 31) == 0); // must be 0 ⩽ handle ⩽ 0x7FFFFFFF
return (1 << 31) | handle;
}
HANDLE fd_to_handle(int fd)
{
if (fd >= 0)
return (HANDLE)_get_osfhandle(fd);
if (fd == -1)
return INVALID_HANDLE_VALUE;
return (HANDLE)(intptr_t)(fd & ~(1 << 31));
}
ErrorOr<int> open(StringView path, int options, mode_t mode)
{
ByteString string_path = path;
@ -30,10 +75,8 @@ ErrorOr<int> open(StringView path, int options, mode_t mode)
if (::stat(sz_path, &st) == 0 && (st.st_mode & S_IFDIR)) {
HANDLE dir_handle = CreateFile(sz_path, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (dir_handle == INVALID_HANDLE_VALUE)
return Error::from_windows_error(GetLastError());
int dir_fd = _open_osfhandle((intptr_t)dir_handle, 0);
if (dir_fd != -1)
return dir_fd;
return Error::from_windows_error();
return handle_to_fd(dir_handle, DirectoryHandle);
}
return Error::from_syscall("open"sv, -error);
}
@ -42,6 +85,20 @@ ErrorOr<int> open(StringView path, int options, mode_t mode)
ErrorOr<void> close(int fd)
{
if (fd < 0) {
HANDLE handle = fd_to_handle(fd);
if (handle == INVALID_HANDLE_VALUE)
return Error::from_string_literal("Invalid file descriptor");
if (is_socket(fd)) {
if (closesocket((SOCKET)handle))
return Error::from_windows_error();
} else {
if (!CloseHandle(handle))
return Error::from_windows_error();
}
return {};
}
if (_close(fd) < 0)
return Error::from_syscall("close"sv, -errno);
return {};
@ -83,8 +140,8 @@ ErrorOr<void> ftruncate(int fd, off_t length)
if (result.is_error())
return result.release_error();
if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0)
return Error::from_windows_error(GetLastError());
if (SetEndOfFile(fd_to_handle(fd)) == 0)
return Error::from_windows_error();
return {};
}
@ -189,4 +246,38 @@ int getpid()
return GetCurrentProcessId();
}
ErrorOr<int> dup(int fd)
{
if (fd < 0) {
HANDLE handle = fd_to_handle(fd);
if (handle == INVALID_HANDLE_VALUE)
return Error::from_string_literal("Invalid file descriptor");
if (is_socket(fd)) {
WSAPROTOCOL_INFO pi = {};
if (WSADuplicateSocket((SOCKET)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 handle_to_fd(socket, SocketHandle);
} else {
if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
return Error::from_windows_error();
return handle_to_fd(handle, FileMappingHandle);
}
}
int new_fd = _dup(fd);
if (new_fd < 0)
return Error::from_syscall("dup"sv, -errno);
return new_fd;
}
bool is_socket(int fd)
{
int val, len = sizeof(val);
return !::getsockopt((SOCKET)fd_to_handle(fd), SOL_SOCKET, SO_TYPE, (char*)&val, &len);
}
}