Skip to content

Commit 711f6bd

Browse files
author
Semphris
committed
Fix Windows support for temp files
1 parent 9c67348 commit 711f6bd

File tree

6 files changed

+104
-13
lines changed

6 files changed

+104
-13
lines changed

src/dynapi/SDL_dynapi.sym

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,9 @@ SDL3_0.0.0 {
11711171
SDL_wcsnstr;
11721172
SDL_wcsstr;
11731173
SDL_wcstol;
1174+
SDL_CreateSafeTempFile;
1175+
SDL_CreateUnsafeTempFile;
1176+
SDL_CreateTempFolder;
11741177
# extra symbols go here (don't modify this line)
11751178
local: *;
11761179
};

src/dynapi/SDL_dynapi_overrides.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,3 +1196,6 @@
11961196
#define SDL_wcsnstr SDL_wcsnstr_REAL
11971197
#define SDL_wcsstr SDL_wcsstr_REAL
11981198
#define SDL_wcstol SDL_wcstol_REAL
1199+
#define SDL_CreateSafeTempFile SDL_CreateSafeTempFile_REAL
1200+
#define SDL_CreateUnsafeTempFile SDL_CreateUnsafeTempFile_REAL
1201+
#define SDL_CreateTempFolder SDL_CreateTempFolder_REAL

src/dynapi/SDL_dynapi_procs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,3 +1202,6 @@ SDL_DYNAPI_PROC(size_t,SDL_wcsnlen,(const wchar_t *a, size_t b),(a,b),return)
12021202
SDL_DYNAPI_PROC(wchar_t*,SDL_wcsnstr,(const wchar_t *a, const wchar_t *b, size_t c),(a,b,c),return)
12031203
SDL_DYNAPI_PROC(wchar_t*,SDL_wcsstr,(const wchar_t *a, const wchar_t *b),(a,b),return)
12041204
SDL_DYNAPI_PROC(long,SDL_wcstol,(const wchar_t *a, wchar_t **b, int c),(a,b,c),return)
1205+
SDL_DYNAPI_PROC(SDL_IOStream*,SDL_CreateSafeTempFile,(void),(),return)
1206+
SDL_DYNAPI_PROC(char*,SDL_CreateUnsafeTempFile,(void),(),return)
1207+
SDL_DYNAPI_PROC(char*,SDL_CreateTempFolder,(void),(),return)

src/filesystem/windows/SDL_sysfilesystem.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -360,13 +360,22 @@ SDL_IOStream *SDL_SYS_CreateSafeTempFile(void)
360360
return NULL;
361361
}
362362

363+
/* Note: Someone watching the temp folder could create a file with a
364+
clashing name before it is re-created (TOCTOU). However, this shouldn't
365+
give access to the contents of the file, because it will be created with
366+
CREATE_NEW. */
363367
UINT id = GetTempFileNameW(tmp_folder, L"tmp", 0, tmp_file);
364368

365369
if (id == 0 || tmp_len > MAX_PATH) {
366370
WIN_SetError("Couldn't get a temporary file");
367371
return NULL;
368372
}
369373

374+
if (!DeleteFileW(tmp_file)) {
375+
WIN_SetError("Couldn't delete the file created by GetTempFileNameW");
376+
return NULL;
377+
}
378+
370379
hFile = CreateFileW(tmp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW,
371380
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
372381

@@ -382,7 +391,6 @@ char *SDL_SYS_CreateUnsafeTempFile(void)
382391
{
383392
wchar_t tmp_folder[MAX_PATH];
384393
wchar_t tmp_file[MAX_PATH];
385-
HANDLE hFile;
386394

387395
/* There exists GetTempPath2W, which is available only on Windows 11+ */
388396
DWORD tmp_len = GetTempPathW(MAX_PATH, tmp_folder);
@@ -399,18 +407,6 @@ char *SDL_SYS_CreateUnsafeTempFile(void)
399407
return NULL;
400408
}
401409

402-
/* TODO: See if there is any advantage to FILE_ATTRIBUTE_TEMPORARY if the
403-
file is immediately closed. */
404-
hFile = CreateFileW(tmp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL,
405-
CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL);
406-
407-
if (hFile == INVALID_HANDLE_VALUE) {
408-
WIN_SetError("Couldn't touch the temporary file");
409-
return NULL;
410-
}
411-
412-
CloseHandle(hFile);
413-
414410
return WIN_StringToUTF8W(tmp_file);
415411
}
416412

@@ -434,6 +430,11 @@ char *SDL_SYS_CreateTempFolder(void)
434430
return NULL;
435431
}
436432

433+
if (!DeleteFileW(tmp_file)) {
434+
WIN_SetError("Couldn't delete the file created by GetTempFileNameW");
435+
return NULL;
436+
}
437+
437438
if (!CreateDirectory(tmp_file, NULL)) {
438439
WIN_SetError("Couldn't create temporary subfolder");
439440
return NULL;

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ add_sdl_test_executable(testdialog SOURCES testdialog.c)
404404
add_sdl_test_executable(testtime SOURCES testtime.c)
405405
add_sdl_test_executable(testmanymouse SOURCES testmanymouse.c)
406406
add_sdl_test_executable(testmodal SOURCES testmodal.c)
407+
add_sdl_test_executable(testtmp SOURCES testtmp.c)
407408

408409
if (HAVE_WAYLAND)
409410
# Set the GENERATED property on the protocol file, since it is first created at build time

test/testtmp.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include <SDL3/SDL.h>
2+
#include <SDL3/SDL_main.h>
3+
#include <SDL3/SDL_test.h>
4+
5+
int main(int argc, char *argv[])
6+
{
7+
SDLTest_CommonState *state;
8+
int i;
9+
char *file;
10+
char *folder;
11+
SDL_IOStream *s;
12+
char buf[7];
13+
14+
/* Initialize test framework */
15+
state = SDLTest_CommonCreateState(argv, 0);
16+
if (state == NULL) {
17+
return 1;
18+
}
19+
20+
/* Parse commandline */
21+
for (i = 1; i < argc;) {
22+
int consumed;
23+
24+
consumed = SDLTest_CommonArg(state, i);
25+
26+
if (consumed <= 0) {
27+
static const char *options[] = { NULL };
28+
SDLTest_CommonLogUsage(state, argv[0], options);
29+
return 1;
30+
}
31+
32+
i += consumed;
33+
}
34+
35+
if (!SDL_Init(SDL_INIT_VIDEO)) {
36+
SDL_Log("SDL_Init failed (%s)", SDL_GetError());
37+
return 1;
38+
}
39+
40+
file = SDL_CreateUnsafeTempFile();
41+
42+
if (file) {
43+
SDL_Log("FILE: %s\n", file);
44+
SDL_RemovePath(file);
45+
SDL_free(file);
46+
} else {
47+
SDL_Log("No temp file: %s\n", SDL_GetError());
48+
}
49+
50+
folder = SDL_CreateTempFolder();
51+
52+
if (folder) {
53+
SDL_Log("FOLDER: %s\n", folder);
54+
SDL_RemovePath(folder);
55+
SDL_free(folder);
56+
} else {
57+
SDL_Log("No temp folder: %s\n", SDL_GetError());
58+
}
59+
60+
s = SDL_CreateSafeTempFile();
61+
62+
if (s) {
63+
SDL_WriteIO(s, "Hello!", 6);
64+
SDL_SeekIO(s, 0, SDL_IO_SEEK_SET);
65+
SDL_ReadIO(s, buf, 6);
66+
SDL_CloseIO(s);
67+
68+
/* The file should be deleted by now. */
69+
70+
buf[6] = '\0';
71+
SDL_Log("SECURE FILE: '%s'\n", buf);
72+
} else {
73+
SDL_Log("No secure temp file: %s\n", SDL_GetError());
74+
}
75+
76+
SDL_Quit();
77+
SDLTest_CommonDestroyState(state);
78+
79+
return 0;
80+
}

0 commit comments

Comments
 (0)