io: With stdio, only forbid opening directories as files.

This allows opening Unix device nodes, etc.

Fixes #15188.
This commit is contained in:
Ryan C. Gordon
2026-03-12 11:36:42 -04:00
parent 4d675f2bd3
commit 9f19cffc78

View File

@@ -970,16 +970,13 @@ static bool SDLCALL mem_close(void *userdata)
#endif
#if defined(HAVE_STDIO_H) && !defined(SKIP_STDIO_DIR_TEST)
static bool IsRegularFileOrPipe(FILE *f)
static bool IsStdioFileADirectory(FILE *f)
{
struct stat st;
if (fstat(fileno(f), &st) < 0 || !(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode))) {
return false;
}
return true;
return ((fstat(fileno(f), &st) == 0) && (S_ISDIR(st.st_mode)));
}
#else
#define IsRegularFileOrPipe(f) false
#define IsStdioFileADirectory(f) false
#endif
SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
@@ -1001,9 +998,9 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
if (*file == '/') {
FILE *fp = fopen(file, mode);
if (fp) {
if (!IsRegularFileOrPipe(fp)) {
if (IsStdioFileADirectory(fp)) {
fclose(fp);
SDL_SetError("%s is not a regular file or pipe", file);
SDL_SetError("%s is a directory", file);
return NULL;
}
return SDL_IOFromFP(fp, true);
@@ -1032,9 +1029,9 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
FILE *fp = fopen(path, mode);
SDL_free(path);
if (fp) {
if (!IsRegularFileOrPipe(fp)) {
if (IsStdioFileADirectory(fp)) {
fclose(fp);
SDL_SetError("%s is not a regular file or pipe", path);
SDL_SetError("%s is a directory", path);
return NULL;
}
return SDL_IOFromFP(fp, true);
@@ -1098,9 +1095,9 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
if (!fp) {
SDL_SetError("Couldn't open %s: %s", file, strerror(errno));
} else if (!IsRegularFileOrPipe(fp)) {
} else if (IsStdioFileADirectory(fp)) {
fclose(fp);
SDL_SetError("%s is not a regular file or pipe", file);
SDL_SetError("%s is a directory", file);
} else {
iostr = SDL_IOFromFP(fp, true);
}
@@ -1121,9 +1118,9 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
if (!fp) {
SDL_SetError("Couldn't open %s: %s", file, strerror(errno));
} else if (!IsRegularFileOrPipe(fp)) {
} else if (IsStdioFileADirectory(fp)) {
fclose(fp);
SDL_SetError("%s is not a regular file or pipe", file);
SDL_SetError("%s is a directory", file);
} else {
iostr = SDL_IOFromFP(fp, true);
}