From eea8090f8422ad3545d024042e91990f11a0c721 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 6 Dec 2025 12:45:05 -0800
Subject: [PATCH] Steam storage improvements
* Implemented EnumerateStorageDirectory()
* Implemented RemoveStoragePath()
* Fixed init failure if the application previously crashed with a write batch in progress
* Allow creation of multiple Steam storage objects, the write batch is complete when the last storage is closed
* Check to see if a file exists in GetStoragePathInfo()
---
src/storage/steam/SDL_steamstorage.c | 105 ++++++++++++++++++++--
src/storage/steam/SDL_steamstorage_proc.h | 6 ++
2 files changed, 102 insertions(+), 9 deletions(-)
diff --git a/src/storage/steam/SDL_steamstorage.c b/src/storage/steam/SDL_steamstorage.c
index 8a939665ef3fa..0148e32320f7b 100644
--- a/src/storage/steam/SDL_steamstorage.c
+++ b/src/storage/steam/SDL_steamstorage.c
@@ -55,15 +55,20 @@ typedef struct STEAM_RemoteStorage
#include "SDL_steamstorage_proc.h"
} STEAM_RemoteStorage;
+static SDL_AtomicInt SDL_steam_storage_refcount;
+
static bool STEAM_CloseStorage(void *userdata)
{
bool result = true;
STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata;
void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016();
+ bool end_batch = SDL_AtomicDecRef(&SDL_steam_storage_refcount);
if (steamremotestorage == NULL) {
result = SDL_SetError("SteamRemoteStorage unavailable");
- } else if (!steam->SteamAPI_ISteamRemoteStorage_EndFileWriteBatch(steamremotestorage)) {
- result = SDL_SetError("SteamRemoteStorage()->EndFileWriteBatch() failed");
+ } else if (end_batch) {
+ if (!steam->SteamAPI_ISteamRemoteStorage_EndFileWriteBatch(steamremotestorage)) {
+ result = SDL_SetError("SteamRemoteStorage()->EndFileWriteBatch() failed");
+ }
}
SDL_UnloadObject(steam->libsteam_api);
SDL_free(steam);
@@ -75,6 +80,67 @@ static bool STEAM_StorageReady(void *userdata)
return true;
}
+static bool STEAM_EnumerateStorageDirectory(void *userdata, const char *path, SDL_EnumerateDirectoryCallback callback, void *callback_userdata)
+{
+ bool result = true;
+ STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata;
+ void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016();
+ if (steamremotestorage == NULL) {
+ return SDL_SetError("SteamRemoteStorage unavailable");
+ }
+
+ const char *prefix;
+ if (SDL_strcmp(path, ".") == 0) {
+ prefix = "";
+ } else {
+ prefix = path;
+ while (*prefix == '/') {
+ ++prefix;
+ }
+ }
+ size_t prefixlen = SDL_strlen(prefix);
+ while (prefixlen > 0 && prefix[prefixlen - 1] == '/') {
+ --prefixlen;
+ }
+
+ bool done = false;
+ Sint32 count = steam->SteamAPI_ISteamRemoteStorage_GetFileCount(steamremotestorage);
+ for (Sint32 i = 0; i < count && !done; ++i) {
+ const char *file = steam->SteamAPI_ISteamRemoteStorage_GetFileNameAndSize(steamremotestorage, i, NULL);
+ if (!file) {
+ continue;
+ }
+
+ const char *fname;
+ if (prefixlen > 0) {
+ // Make sure the prefix matches
+ if (SDL_strncmp(prefix, file, prefixlen) != 0 || *(file + prefixlen) != '/') {
+ continue;
+ }
+ fname = file + prefixlen + 1;
+ } else {
+ // Make sure this is a top-level file
+ if (SDL_strchr(file, '/') != NULL) {
+ continue;
+ }
+ fname = file;
+ }
+
+ switch (callback(callback_userdata, path, fname)) {
+ case SDL_ENUM_SUCCESS:
+ done = true;
+ break;
+ case SDL_ENUM_FAILURE:
+ result = false;
+ done = true;
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
static bool STEAM_GetStoragePathInfo(void *userdata, const char *path, SDL_PathInfo *info)
{
STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata;
@@ -83,10 +149,16 @@ static bool STEAM_GetStoragePathInfo(void *userdata, const char *path, SDL_PathI
return SDL_SetError("SteamRemoteStorage unavailable");
}
+ if (!steam->SteamAPI_ISteamRemoteStorage_FileExists(steamremotestorage, path)) {
+ return SDL_SetError("Can't stat");
+ }
+
if (info) {
SDL_zerop(info);
info->type = SDL_PATHTYPE_FILE;
info->size = steam->SteamAPI_ISteamRemoteStorage_GetFileSize(steamremotestorage, path);
+ Sint64 mtime = steam->SteamAPI_ISteamRemoteStorage_GetFileTimestamp(steamremotestorage, path);
+ info->modify_time = (SDL_Time)SDL_SECONDS_TO_NS(mtime);
}
return true;
}
@@ -129,6 +201,19 @@ static bool STEAM_WriteStorageFile(void *userdata, const char *path, const void
return result;
}
+static bool STEAM_RemoveStoragePath(void *userdata, const char *path)
+{
+ STEAM_RemoteStorage *steam = (STEAM_RemoteStorage *)userdata;
+ void *steamremotestorage = steam->SteamAPI_SteamRemoteStorage_v016();
+ if (steamremotestorage == NULL) {
+ return SDL_SetError("SteamRemoteStorage unavailable");
+ }
+ if (!steam->SteamAPI_ISteamRemoteStorage_FileDelete(steamremotestorage, path)) {
+ return SDL_SetError("SteamRemoteStorage()->FileDelete() failed");
+ }
+ return true;
+}
+
static Uint64 STEAM_GetStorageSpaceRemaining(void *userdata)
{
Uint64 total, remaining;
@@ -149,12 +234,12 @@ static const SDL_StorageInterface STEAM_user_iface = {
sizeof(SDL_StorageInterface),
STEAM_CloseStorage,
STEAM_StorageReady,
- NULL, // enumerate
+ STEAM_EnumerateStorageDirectory,
STEAM_GetStoragePathInfo,
STEAM_ReadStorageFile,
STEAM_WriteStorageFile,
NULL, // mkdir
- NULL, // remove
+ STEAM_RemoveStoragePath,
NULL, // rename
NULL, // copy
STEAM_GetStorageSpaceRemaining
@@ -198,15 +283,17 @@ static SDL_Storage *STEAM_User_Create(const char *org, const char *app, SDL_Prop
SDL_SetError("Steam cloud is disabled for this application");
goto steamfail;
}
- if (!steam->SteamAPI_ISteamRemoteStorage_BeginFileWriteBatch(steamremotestorage)) {
- SDL_SetError("SteamRemoteStorage()->BeginFileWriteBatch() failed");
- goto steamfail;
- }
result = SDL_OpenStorage(&STEAM_user_iface, steam);
- if (result == NULL) {
+ if (!result) {
goto steamfail;
}
+
+ if (SDL_AtomicIncRef(&SDL_steam_storage_refcount) == 0) {
+ if (!steam->SteamAPI_ISteamRemoteStorage_BeginFileWriteBatch(steamremotestorage)) {
+ // We probably already have a batch in progress (maybe we crashed earlier?)
+ }
+ }
return result;
steamfail:
diff --git a/src/storage/steam/SDL_steamstorage_proc.h b/src/storage/steam/SDL_steamstorage_proc.h
index 9d259e70d1ff9..7aa957fc6a119 100644
--- a/src/storage/steam/SDL_steamstorage_proc.h
+++ b/src/storage/steam/SDL_steamstorage_proc.h
@@ -6,9 +6,15 @@ STEAM_PROC(bool, SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp, (void*))
STEAM_PROC(bool, SteamAPI_ISteamRemoteStorage_BeginFileWriteBatch, (void*))
STEAM_PROC(bool, SteamAPI_ISteamRemoteStorage_EndFileWriteBatch, (void*))
+STEAM_PROC(bool, SteamAPI_ISteamRemoteStorage_FileExists, (void*, const char*))
STEAM_PROC(Sint32, SteamAPI_ISteamRemoteStorage_GetFileSize, (void*, const char*))
+STEAM_PROC(Sint64, SteamAPI_ISteamRemoteStorage_GetFileTimestamp, (void*, const char *))
STEAM_PROC(Sint32, SteamAPI_ISteamRemoteStorage_FileRead, (void*, const char*, void*, Sint32))
STEAM_PROC(Sint32, SteamAPI_ISteamRemoteStorage_FileWrite, (void*, const char*, const void*, Sint32))
+STEAM_PROC(bool, SteamAPI_ISteamRemoteStorage_FileDelete, (void*, const char*))
STEAM_PROC(bool, SteamAPI_ISteamRemoteStorage_GetQuota, (void*, Uint64*, Uint64*))
+STEAM_PROC(Sint32, SteamAPI_ISteamRemoteStorage_GetFileCount, (void*))
+STEAM_PROC(const char *, SteamAPI_ISteamRemoteStorage_GetFileNameAndSize, (void*, int, Sint32*))
+
#undef STEAM_PROC