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