mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Rework base IO functions on Windows using HANDLE
Switch to using the Windows-specific `HANDLE` and Windows API functions instead of `FILE *` and standard library functions in all Windows IO function implementations. Using `CreateFileW` instead of `_wfsopen` to open files is necessary, as only `CreateFileW` allows specifying all necessary sharing flags. The sharing flags `FILE_SHARE_READ` and `FILE_SHARE_WRITE` were previously already specified by using `_SH_DENYNO` with `_wfsopen`, but `FILE_SHARE_DELETE` can only be set when using `CreateFileW`. The flags are necessary so files which are in use by the game can still be opened by other processes. In particular, `FILE_SHARE_DELETE` allows deleting/renaming of open files, which was previously not possible. This was causing the smart editor saving process that renames files to fail if a map file is currently in use. Because `CreateFileW` returns a `HANDLE` instead of a `FILE *` we have to use the `HANDLE`-based Windows IO functions everywhere. See: https://devblogs.microsoft.com/oldnewthing/20211022-00/?p=105822 Closes #6922.
This commit is contained in:
parent
03fd1b440b
commit
ef5ffedee6
|
@ -7,7 +7,7 @@
|
|||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
typedef struct IOINTERNAL *IOHANDLE;
|
||||
typedef void *IOHANDLE;
|
||||
|
||||
/**
|
||||
* @ingroup Log
|
||||
|
|
|
@ -91,10 +91,30 @@
|
|||
|
||||
IOHANDLE io_stdin()
|
||||
{
|
||||
return (IOHANDLE)stdin;
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
return GetStdHandle(STD_INPUT_HANDLE);
|
||||
#else
|
||||
return stdin;
|
||||
#endif
|
||||
}
|
||||
|
||||
IOHANDLE io_stdout()
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
return GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
#else
|
||||
return stdout;
|
||||
#endif
|
||||
}
|
||||
|
||||
IOHANDLE io_stderr()
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
return GetStdHandle(STD_ERROR_HANDLE);
|
||||
#else
|
||||
return stderr;
|
||||
#endif
|
||||
}
|
||||
IOHANDLE io_stdout() { return (IOHANDLE)stdout; }
|
||||
IOHANDLE io_stderr() { return (IOHANDLE)stderr; }
|
||||
|
||||
IOHANDLE io_current_exe()
|
||||
{
|
||||
|
@ -258,21 +278,52 @@ IOHANDLE io_open_impl(const char *filename, int flags)
|
|||
dbg_assert(flags == (IOFLAG_READ | IOFLAG_SKIP_BOM) || flags == IOFLAG_READ || flags == IOFLAG_WRITE || flags == IOFLAG_APPEND, "flags must be read, read+skipbom, write or append");
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
const std::wstring wide_filename = windows_utf8_to_wide(filename);
|
||||
DWORD desired_access;
|
||||
DWORD creation_disposition;
|
||||
if((flags & IOFLAG_READ) != 0)
|
||||
return (IOHANDLE)_wfsopen(wide_filename.c_str(), L"rb", _SH_DENYNO);
|
||||
if(flags == IOFLAG_WRITE)
|
||||
return (IOHANDLE)_wfsopen(wide_filename.c_str(), L"wb", _SH_DENYNO);
|
||||
if(flags == IOFLAG_APPEND)
|
||||
return (IOHANDLE)_wfsopen(wide_filename.c_str(), L"ab", _SH_DENYNO);
|
||||
return 0x0;
|
||||
{
|
||||
desired_access = FILE_READ_DATA;
|
||||
creation_disposition = OPEN_EXISTING;
|
||||
}
|
||||
else if(flags == IOFLAG_WRITE)
|
||||
{
|
||||
desired_access = FILE_WRITE_DATA;
|
||||
creation_disposition = OPEN_ALWAYS;
|
||||
}
|
||||
else if(flags == IOFLAG_APPEND)
|
||||
{
|
||||
desired_access = FILE_APPEND_DATA;
|
||||
creation_disposition = OPEN_ALWAYS;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_assert(false, "logic error");
|
||||
return nullptr;
|
||||
}
|
||||
HANDLE handle = CreateFileW(wide_filename.c_str(), desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, creation_disposition, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if(handle == INVALID_HANDLE_VALUE)
|
||||
return nullptr; // otherwise all existing checks don't work for the invalid handle
|
||||
return handle;
|
||||
#else
|
||||
const char *open_mode;
|
||||
if((flags & IOFLAG_READ) != 0)
|
||||
return (IOHANDLE)fopen(filename, "rb");
|
||||
if(flags == IOFLAG_WRITE)
|
||||
return (IOHANDLE)fopen(filename, "wb");
|
||||
if(flags == IOFLAG_APPEND)
|
||||
return (IOHANDLE)fopen(filename, "ab");
|
||||
return 0x0;
|
||||
{
|
||||
open_mode = "rb";
|
||||
}
|
||||
else if(flags == IOFLAG_WRITE)
|
||||
{
|
||||
open_mode = "wb";
|
||||
}
|
||||
else if(flags == IOFLAG_APPEND)
|
||||
{
|
||||
open_mode = "ab";
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_assert(false, "logic error");
|
||||
return nullptr;
|
||||
}
|
||||
return fopen(filename, open_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -293,7 +344,13 @@ IOHANDLE io_open(const char *filename, int flags)
|
|||
|
||||
unsigned io_read(IOHANDLE io, void *buffer, unsigned size)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
DWORD actual_size;
|
||||
ReadFile((HANDLE)io, buffer, size, &actual_size, nullptr);
|
||||
return actual_size;
|
||||
#else
|
||||
return fread(buffer, 1, size, (FILE *)io);
|
||||
#endif
|
||||
}
|
||||
|
||||
void io_read_all(IOHANDLE io, void **result, unsigned *result_len)
|
||||
|
@ -343,14 +400,31 @@ char *io_read_all_str(IOHANDLE io)
|
|||
|
||||
unsigned io_skip(IOHANDLE io, int size)
|
||||
{
|
||||
fseek((FILE *)io, size, SEEK_CUR);
|
||||
return size;
|
||||
return io_seek(io, size, IOSEEK_CUR);
|
||||
}
|
||||
|
||||
int io_seek(IOHANDLE io, int offset, int origin)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
DWORD move_method;
|
||||
switch(origin)
|
||||
{
|
||||
case IOSEEK_START:
|
||||
move_method = FILE_BEGIN;
|
||||
break;
|
||||
case IOSEEK_CUR:
|
||||
move_method = FILE_CURRENT;
|
||||
break;
|
||||
case IOSEEK_END:
|
||||
move_method = FILE_END;
|
||||
break;
|
||||
default:
|
||||
dbg_assert(false, "origin invalid");
|
||||
return -1;
|
||||
}
|
||||
return SetFilePointer((HANDLE)io, offset, nullptr, move_method) == INVALID_SET_FILE_POINTER ? -1 : 0;
|
||||
#else
|
||||
int real_origin;
|
||||
|
||||
switch(origin)
|
||||
{
|
||||
case IOSEEK_START:
|
||||
|
@ -363,15 +437,21 @@ int io_seek(IOHANDLE io, int offset, int origin)
|
|||
real_origin = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
dbg_assert(false, "origin invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fseek((FILE *)io, offset, real_origin);
|
||||
#endif
|
||||
}
|
||||
|
||||
long int io_tell(IOHANDLE io)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
const DWORD position = SetFilePointer((HANDLE)io, 0, nullptr, FILE_CURRENT);
|
||||
return position == INVALID_SET_FILE_POINTER ? -1 : position;
|
||||
#else
|
||||
return ftell((FILE *)io);
|
||||
#endif
|
||||
}
|
||||
|
||||
long int io_length(IOHANDLE io)
|
||||
|
@ -385,12 +465,23 @@ long int io_length(IOHANDLE io)
|
|||
|
||||
int io_error(IOHANDLE io)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
// Only works when called directly after the operation that failed
|
||||
return GetLastError();
|
||||
#else
|
||||
return ferror((FILE *)io);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned io_write(IOHANDLE io, const void *buffer, unsigned size)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
DWORD actual_size;
|
||||
WriteFile((HANDLE)io, buffer, size, &actual_size, nullptr);
|
||||
return actual_size;
|
||||
#else
|
||||
return fwrite(buffer, 1, size, (FILE *)io);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool io_write_newline(IOHANDLE io)
|
||||
|
@ -404,12 +495,20 @@ bool io_write_newline(IOHANDLE io)
|
|||
|
||||
int io_close(IOHANDLE io)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
return CloseHandle((HANDLE)io) == 0;
|
||||
#else
|
||||
return fclose((FILE *)io) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int io_flush(IOHANDLE io)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
return FlushFileBuffers((HANDLE)io) == FALSE;
|
||||
#else
|
||||
return fflush((FILE *)io);
|
||||
#endif
|
||||
}
|
||||
|
||||
int io_sync(IOHANDLE io)
|
||||
|
@ -419,7 +518,7 @@ int io_sync(IOHANDLE io)
|
|||
return 1;
|
||||
}
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
return FlushFileBuffers((HANDLE)_get_osfhandle(_fileno((FILE *)io))) == 0;
|
||||
return FlushFileBuffers((HANDLE)io) == 0;
|
||||
#else
|
||||
return fsync(fileno((FILE *)io)) != 0;
|
||||
#endif
|
||||
|
|
|
@ -223,7 +223,7 @@ enum
|
|||
IO_MAX_PATH_LENGTH = 512,
|
||||
};
|
||||
|
||||
typedef struct IOINTERNAL *IOHANDLE;
|
||||
typedef void *IOHANDLE;
|
||||
|
||||
/**
|
||||
* Opens a file.
|
||||
|
|
Loading…
Reference in a new issue