diff --git a/include/SDL3/SDL_iostream.h b/include/SDL3/SDL_iostream.h index 0fb3271854..37cd4330cc 100644 --- a/include/SDL3/SDL_iostream.h +++ b/include/SDL3/SDL_iostream.h @@ -203,6 +203,8 @@ typedef struct SDL_IOStream SDL_IOStream; * - "w": Create an empty file for writing. If a file with the same name * already exists its content is erased and the file is treated as a new * empty file. + * - "wx": Create an empty file for writing. If a file with the same name + * already exists, the call fails. * - "a": Append to a file. Writing operations append data at the end of the * file. The file is created if it does not exist. * - "r+": Open a file for update both reading and writing. The file must @@ -210,6 +212,8 @@ typedef struct SDL_IOStream SDL_IOStream; * - "w+": Create an empty file for both reading and writing. If a file with * the same name already exists its content is erased and the file is * treated as a new empty file. + * - "w+x": Create an empty file for both reading and writing. If a file with + * the same name already exists, the call fails. * - "a+": Open a file for reading and appending. All writing operations are * performed at the end of the file, protecting the previous content to be * overwritten. You can reposition (fseek, rewind) the internal pointer to diff --git a/src/io/SDL_iostream.c b/src/io/SDL_iostream.c index cc435da2fb..04c6c94629 100644 --- a/src/io/SDL_iostream.c +++ b/src/io/SDL_iostream.c @@ -94,10 +94,12 @@ static HANDLE SDLCALL windows_file_open(const char *filename, const char *mode) // "r" = reading, file must exist // "w" = writing, truncate existing, file may not exist + // "wx"= writing, file must not exist // "r+"= reading or writing, file must exist // "a" = writing, append file may not exist // "a+"= append + read, file may not exist // "w+" = read, write, truncate. file may not exist + // "w+x"= read, write, file must not exist must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0; truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0; @@ -105,6 +107,10 @@ static HANDLE SDLCALL windows_file_open(const char *filename, const char *mode) a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0; w_right = (a_mode || SDL_strchr(mode, '+') || truncate) ? GENERIC_WRITE : 0; + if (truncate && (SDL_strchr(mode, 'x') != NULL)) { + truncate = CREATE_NEW; + } + if (!r_right && !w_right) { return INVALID_HANDLE_VALUE; // inconsistent mode } diff --git a/test/testautomation_iostream.c b/test/testautomation_iostream.c index 85bfc71498..240aaf9f0d 100644 --- a/test/testautomation_iostream.c +++ b/test/testautomation_iostream.c @@ -615,9 +615,9 @@ static int SDLCALL iostrm_testFileWrite(void *arg) int result; /* Write test. */ - rw = SDL_IOFromFile(IOStreamWriteTestFilename, "w+"); - SDLTest_AssertPass("Call to SDL_IOFromFile(..,\"w+\") succeeded"); - SDLTest_AssertCheck(rw != NULL, "Verify opening file with SDL_IOFromFile in write mode does not return NULL"); + rw = SDL_IOFromFile(IOStreamWriteTestFilename, "w+x"); + SDLTest_AssertPass("Call to SDL_IOFromFile(..,\"w+x\") succeeded"); + SDLTest_AssertCheck(rw != NULL, "Verify opening file with SDL_IOFromFile in exclusive write mode does not return NULL"); /* Bail out if NULL */ if (rw == NULL) { @@ -632,6 +632,11 @@ static int SDLCALL iostrm_testFileWrite(void *arg) SDLTest_AssertPass("Call to SDL_CloseIO() succeeded"); SDLTest_AssertCheck(result == true, "Verify result value is true; got: %d", result); + /* Exclusively opening an existing file should fail. */ + rw = SDL_IOFromFile(IOStreamWriteTestFilename, "wx"); + SDLTest_AssertPass("Call to SDL_IOFromFile(..,\"wx\") succeeded"); + SDLTest_AssertCheck(rw == NULL, "Verify opening existing file with SDL_IOFromFile in exclusive write mode returns NULL"); + return TEST_COMPLETED; }