asyncio: don't report failures on closing read-only files with Windows IoRing.

We still need the task to go through the IoRing, even though the flush
operation we use to get it there will always fail on a read-only file. So
check for this specific case and don't report failure.

Fixes #14878.

(cherry picked from commit 4df13e8806)
This commit is contained in:
Ryan C. Gordon
2026-01-31 03:58:25 -05:00
committed by Sam Lantinga
parent de5e0f1784
commit c3e92cf1c4
3 changed files with 22 additions and 9 deletions

View File

@@ -23,20 +23,23 @@
#include "SDL_sysasyncio.h"
#include "SDL_asyncio_c.h"
static const char *AsyncFileModeValid(const char *mode)
static const char *AsyncFileModeValid(const char *mode, bool *readonly)
{
static const struct { const char *valid; const char *with_binary; } mode_map[] = {
{ "r", "rb" },
{ "w", "wb" },
{ "r+","r+b" },
{ "w+", "w+b" }
static const struct { const char *valid; const char *with_binary; bool readonly; } mode_map[] = {
{ "r", "rb", true },
{ "w", "wb", false },
{ "r+","r+b", false },
{ "w+", "w+b", false }
};
for (int i = 0; i < SDL_arraysize(mode_map); i++) {
if (SDL_strcmp(mode, mode_map[i].valid) == 0) {
*readonly = mode_map[i].readonly;
return mode_map[i].with_binary;
}
}
*readonly = false;
return NULL;
}
@@ -51,7 +54,8 @@ SDL_AsyncIO *SDL_AsyncIOFromFile(const char *file, const char *mode)
return NULL;
}
const char *binary_mode = AsyncFileModeValid(mode);
bool readonly = false;
const char *binary_mode = AsyncFileModeValid(mode, &readonly);
if (!binary_mode) {
SDL_SetError("Unsupported file mode");
return NULL;
@@ -62,6 +66,8 @@ SDL_AsyncIO *SDL_AsyncIOFromFile(const char *file, const char *mode)
return NULL;
}
asyncio->readonly = readonly;
asyncio->lock = SDL_CreateMutex();
if (!asyncio->lock) {
SDL_free(asyncio);

View File

@@ -124,6 +124,7 @@ struct SDL_AsyncIO
SDL_AsyncIOTask tasks;
SDL_AsyncIOTask *closing; // The close task, which isn't queued until all pending work for this file is done.
bool oneshot; // true if this is a SDL_LoadFileAsync open.
bool readonly; // true if this file is opened read-only.
};
// This is implemented for various platforms; param validation is done before calling this. Open file, fill in iface and userdata.

View File

@@ -200,8 +200,14 @@ static SDL_AsyncIOTask *ProcessCQE(WinIoRingAsyncIOQueueData *queuedata, IORING_
task = NULL; // it already finished or was too far along to cancel, so we'll pick up the actual results later.
}
} else if (FAILED(cqe->ResultCode)) {
task->result = SDL_ASYNCIO_FAILURE;
// !!! FIXME: fill in task->error.
if ((task->type == SDL_ASYNCIO_TASK_CLOSE) && (cqe->ResultCode == E_ACCESSDENIED) && task->asyncio->readonly) {
// we push all close requests through as flushes, as there is currently no async close operation and flushing writes to disk is the time-consuming part.
// However, flushing a read-only handle generates an error, so we catch this specific situation and ignore it. This approach still makes the task go
// through the IoRing so we can handle this all in the same place otherwise. The actual close happens below.
} else {
task->result = SDL_ASYNCIO_FAILURE;
// !!! FIXME: fill in task->error.
}
} else {
if ((task->type == SDL_ASYNCIO_TASK_WRITE) && (((Uint64) cqe->Information) < task->requested_size)) {
task->result = SDL_ASYNCIO_FAILURE; // it's always a failure on short writes.