Browse Source

Merge 78e619804b209f014974e302d0e46e90c7aea7a3 into 3eefa464eef2278f3f8c311aa5905bf6c0bb011e

stasoid 6 months ago
parent
commit
eb83f4a26f

+ 29 - 20
AK/Error.cpp

@@ -10,6 +10,7 @@
 #ifdef AK_OS_WINDOWS
 #ifdef AK_OS_WINDOWS
 #    include <AK/ByteString.h>
 #    include <AK/ByteString.h>
 #    include <AK/HashMap.h>
 #    include <AK/HashMap.h>
+#    include <stdio.h>
 #    include <windows.h>
 #    include <windows.h>
 #endif
 #endif
 
 
@@ -21,31 +22,39 @@ Error Error::from_string_view_or_print_error_and_return_errno(StringView string_
 }
 }
 
 
 #ifdef AK_OS_WINDOWS
 #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);
     auto string = windows_errors.get(code);
-    if (string.has_value()) {
+    if (string.has_value())
         return Error::from_string_view(string->view());
         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);
-
-        windows_errors.set(code, { message, size });
-        LocalFree(message);
-        return from_windows_error(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);
+
+    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
 #endif
 
 

+ 2 - 6
AK/Error.h

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

+ 9 - 7
Libraries/LibCore/AnonymousBufferWindows.cpp

@@ -6,7 +6,9 @@
  */
  */
 
 
 #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 >> 31 >> 1, size & 0xFFFFFFFF, NULL);
     if (!map_handle)
     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)
 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)
     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)
 ErrorOr<AnonymousBuffer> AnonymousBuffer::create_with_size(size_t size)

+ 4 - 3
Libraries/LibCore/EventLoopImplementationWindows.cpp

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

+ 4 - 4
Libraries/LibCore/ProcessWindows.cpp

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

+ 6 - 0
Libraries/LibCore/System.cpp

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

+ 13 - 0
Libraries/LibCore/System.h

@@ -52,6 +52,18 @@ using socklen_t = int;
 
 
 namespace Core::System {
 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)
 #if !defined(AK_OS_MACOS) && !defined(AK_OS_HAIKU)
 ErrorOr<int> accept4(int sockfd, struct sockaddr*, socklen_t*, int flags);
 ErrorOr<int> accept4(int sockfd, struct sockaddr*, socklen_t*, int flags);
 #endif
 #endif
@@ -180,5 +192,6 @@ ErrorOr<void> set_resource_limits(int resource, rlim_t limit);
 #endif
 #endif
 
 
 int getpid();
 int getpid();
+bool is_socket(int fd);
 
 
 }
 }

+ 99 - 8
Libraries/LibCore/SystemWindows.cpp

@@ -12,13 +12,58 @@
 #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 {
 
 
+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)
 ErrorOr<int> open(StringView path, int options, mode_t mode)
 {
 {
     ByteString string_path = path;
     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)) {
         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);
             HANDLE dir_handle = CreateFile(sz_path, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
             if (dir_handle == INVALID_HANDLE_VALUE)
             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);
         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)
 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)
     if (_close(fd) < 0)
         return Error::from_syscall("close"sv, -errno);
         return Error::from_syscall("close"sv, -errno);
     return {};
     return {};
@@ -83,8 +140,8 @@ ErrorOr<void> ftruncate(int fd, off_t length)
     if (result.is_error())
     if (result.is_error())
         return result.release_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 {};
     return {};
 }
 }
 
 
@@ -189,4 +246,38 @@ int getpid()
     return GetCurrentProcessId();
     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);
+}
+
 }
 }