Browse Source

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()
Sam Lantinga 2 weeks ago
parent
commit
eea8090f84
2 changed files with 102 additions and 9 deletions
  1. 96 9
      src/storage/steam/SDL_steamstorage.c
  2. 6 0
      src/storage/steam/SDL_steamstorage_proc.h

+ 96 - 9
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:

+ 6 - 0
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