Merge 78e619804b
into 3eefa464ee
This commit is contained in:
commit
eb83f4a26f
8 changed files with 164 additions and 46 deletions
45
AK/Error.cpp
45
AK/Error.cpp
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue