SaveData_SystemComponent_Linux.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <SaveDataSystemComponent.h>
  9. #include <AzCore/IO/SystemFile.h>
  10. #include <AzCore/IO/Path/Path.h>
  11. #include <AzCore/std/string/conversions.h>
  12. #include <AzCore/Utils/Utils.h>
  13. #include <AzCore/PlatformIncl.h>
  14. #include <sys/types.h>
  15. #include <pwd.h>
  16. #include <unistd.h>
  17. ////////////////////////////////////////////////////////////////////////////////////////////////////
  18. namespace SaveData
  19. {
  20. ////////////////////////////////////////////////////////////////////////////////////////////////
  21. //! Platform specific implementation for the save data system component on Linux
  22. class SaveDataSystemComponentLinux : public SaveDataSystemComponent::Implementation
  23. {
  24. public:
  25. ////////////////////////////////////////////////////////////////////////////////////////////
  26. static constexpr const char* DefaultSaveDataDirectoryName = "SaveData";
  27. ////////////////////////////////////////////////////////////////////////////////////////////
  28. // Allocator
  29. AZ_CLASS_ALLOCATOR(SaveDataSystemComponentLinux, AZ::SystemAllocator);
  30. ////////////////////////////////////////////////////////////////////////////////////////////
  31. //! Constructor
  32. //! \param[in] saveDataSystemComponent Reference to the parent being implemented
  33. SaveDataSystemComponentLinux(SaveDataSystemComponent& saveDataSystemComponent);
  34. ////////////////////////////////////////////////////////////////////////////////////////////
  35. //! Destructor
  36. ~SaveDataSystemComponentLinux() override;
  37. protected:
  38. ////////////////////////////////////////////////////////////////////////////////////////////
  39. //! \ref SaveData::SaveDataSystemComponent::Implementation::SaveDataBuffer
  40. void SaveDataBuffer(const SaveDataRequests::SaveDataBufferParams& saveDataBufferParams) override;
  41. ////////////////////////////////////////////////////////////////////////////////////////////
  42. //! \ref SaveData::SaveDataSystemComponent::Implementation::LoadDataBuffer
  43. void LoadDataBuffer(const SaveDataRequests::LoadDataBufferParams& loadDataBufferParams) override;
  44. ////////////////////////////////////////////////////////////////////////////////////////////
  45. //! \ref SaveData::SaveDataSystemComponent::Implementation::SetSaveDataDirectoryPath
  46. void SetSaveDataDirectoryPath(const char* saveDataDirectoryPath) override;
  47. private:
  48. ////////////////////////////////////////////////////////////////////////////////////////////
  49. //! Convenience function to construct the full save data file path.
  50. //! \param[in] dataBufferName The name of the save data buffer.
  51. //! \param[in] localUserId The local user id the save data buffer is associated with.
  52. AZ::IO::Path GetSaveDataFilePath(const AZStd::string& dataBufferName,
  53. AzFramework::LocalUserId localUserId);
  54. ////////////////////////////////////////////////////////////////////////////////////////////
  55. //! The absolute path to the application's save data dircetory.
  56. AZ::IO::Path m_saveDataDirectoryPathAbsolute;
  57. };
  58. ////////////////////////////////////////////////////////////////////////////////////////////////
  59. AZ::IO::Path GetDefaultLinuxUserSaveDataPath()
  60. {
  61. // First priority for the home directory is the 'HOME' environment variable
  62. const char* homeDir = getenv("HOME");
  63. if (homeDir == nullptr)
  64. {
  65. // If the 'HOME' environment variable is not set, then retrieve it from the 'getpwuid'
  66. // system call
  67. auto uid = getuid();
  68. auto pwuid = getpwuid(uid);
  69. homeDir = pwuid->pw_dir;
  70. }
  71. AZ_Assert(homeDir, "Unable to determine home directory for current Linux user");
  72. if (homeDir == nullptr)
  73. {
  74. homeDir = "/tmp";
  75. }
  76. AZ::IO::Path homePath {homeDir};
  77. // $HOME/.local/share is the standard directory where user data is stored on Ubuntu
  78. return homePath / ".local" / "share";
  79. }
  80. ////////////////////////////////////////////////////////////////////////////////////////////////
  81. AZStd::string GetExecutableName()
  82. {
  83. char moduleFileName[AZ_MAX_PATH_LEN];
  84. AZ::Utils::GetExecutablePath(moduleFileName, AZ_MAX_PATH_LEN);
  85. AZ::IO::Path executableFullPath {moduleFileName};
  86. AZStd::string moduleFileNameString {executableFullPath.Filename().Native()};
  87. return moduleFileNameString;
  88. }
  89. ////////////////////////////////////////////////////////////////////////////////////////////////
  90. SaveDataSystemComponent::Implementation* SaveDataSystemComponent::Implementation::Create(SaveDataSystemComponent& saveDataSystemComponent)
  91. {
  92. return aznew SaveDataSystemComponentLinux(saveDataSystemComponent);
  93. }
  94. ////////////////////////////////////////////////////////////////////////////////////////////////
  95. SaveDataSystemComponentLinux::SaveDataSystemComponentLinux(SaveDataSystemComponent& saveDataSystemComponent)
  96. : SaveDataSystemComponent::Implementation(saveDataSystemComponent)
  97. , m_saveDataDirectoryPathAbsolute(GetDefaultLinuxUserSaveDataPath() /
  98. GetExecutableName().c_str() /
  99. DefaultSaveDataDirectoryName)
  100. {
  101. }
  102. ////////////////////////////////////////////////////////////////////////////////////////////////
  103. SaveDataSystemComponentLinux::~SaveDataSystemComponentLinux()
  104. {
  105. }
  106. ////////////////////////////////////////////////////////////////////////////////////////////////
  107. void SaveDataSystemComponentLinux::SaveDataBuffer(const SaveDataRequests::SaveDataBufferParams& saveDataBufferParams)
  108. {
  109. const AZStd::string absoluteFilePath = GetSaveDataFilePath(saveDataBufferParams.dataBufferName,
  110. saveDataBufferParams.localUserId).c_str();
  111. SaveDataBufferToFileSystem(saveDataBufferParams, absoluteFilePath);
  112. }
  113. ////////////////////////////////////////////////////////////////////////////////////////////////
  114. void SaveDataSystemComponentLinux::LoadDataBuffer(const SaveDataRequests::LoadDataBufferParams& loadDataBufferParams)
  115. {
  116. const AZStd::string absoluteFilePath = GetSaveDataFilePath(loadDataBufferParams.dataBufferName,
  117. loadDataBufferParams.localUserId).c_str();
  118. LoadDataBufferFromFileSystem(loadDataBufferParams, absoluteFilePath);
  119. }
  120. ////////////////////////////////////////////////////////////////////////////////////////////////
  121. void SaveDataSystemComponentLinux::SetSaveDataDirectoryPath(const char* saveDataDirectoryPath)
  122. {
  123. AZ::IO::Path saveDataDirectoryBasicPath { saveDataDirectoryPath };
  124. if (saveDataDirectoryBasicPath.IsAbsolute())
  125. {
  126. m_saveDataDirectoryPathAbsolute = saveDataDirectoryBasicPath;
  127. }
  128. else
  129. {
  130. m_saveDataDirectoryPathAbsolute = GetDefaultLinuxUserSaveDataPath() / saveDataDirectoryBasicPath;
  131. }
  132. AZ_Assert(!m_saveDataDirectoryPathAbsolute.empty(), "Cannot set an empty save data directory path.");
  133. }
  134. ////////////////////////////////////////////////////////////////////////////////////////////////
  135. AZ::IO::Path SaveDataSystemComponentLinux::GetSaveDataFilePath(const AZStd::string& dataBufferName,
  136. AzFramework::LocalUserId localUserId)
  137. {
  138. AZ::IO::Path saveDataFilePath = m_saveDataDirectoryPathAbsolute;
  139. if (localUserId != AzFramework::LocalUserIdNone)
  140. {
  141. saveDataFilePath /= AZStd::string::format("User_%u", localUserId);
  142. }
  143. saveDataFilePath /= dataBufferName;
  144. return saveDataFilePath;
  145. }
  146. } // namespace SaveData