mirror of
				https://github.com/Atmosphere-NX/Atmosphere-libs.git
				synced 2025-10-31 11:36:02 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			146 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) Atmosphère-NX
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify it
 | |
|  * under the terms and conditions of the GNU General Public License,
 | |
|  * version 2, as published by the Free Software Foundation.
 | |
|  *
 | |
|  * This program is distributed in the hope it will be useful, but WITHOUT
 | |
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | |
|  * more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| #include <stratosphere.hpp>
 | |
| 
 | |
| namespace ams::emummc {
 | |
| 
 | |
|     namespace {
 | |
| 
 | |
|         /* Convenience Definitions. */
 | |
|         constexpr u32 StorageMagic = util::FourCC<'E','F','S','0'>::Code;
 | |
|         constexpr size_t MaxDirLen = 0x7F;
 | |
| 
 | |
|         /* Types. */
 | |
|         struct BaseConfig {
 | |
|             u32 magic;
 | |
|             u32 type;
 | |
|             u32 id;
 | |
|             u32 fs_version;
 | |
|         };
 | |
| 
 | |
|         struct PartitionConfig {
 | |
|             u64 start_sector;
 | |
|         };
 | |
| 
 | |
|         struct FileConfig {
 | |
|             char path[MaxDirLen + 1];
 | |
|         };
 | |
| 
 | |
|         struct ExosphereConfig {
 | |
|             BaseConfig base_cfg;
 | |
|             union {
 | |
|                 PartitionConfig partition_cfg;
 | |
|                 FileConfig file_cfg;
 | |
|             };
 | |
|             char emu_dir_path[MaxDirLen + 1];
 | |
|         };
 | |
| 
 | |
|         enum Storage : u32 {
 | |
|             Storage_Emmc,
 | |
|             Storage_Sd,
 | |
|             Storage_SdFile,
 | |
| 
 | |
|             Storage_Count,
 | |
|         };
 | |
| 
 | |
|         /* Globals. */
 | |
|         constinit os::SdkMutex g_lock;
 | |
|         constinit ExosphereConfig g_exo_config = {};
 | |
|         constinit bool g_is_emummc;
 | |
|         constinit bool g_has_cached;
 | |
| 
 | |
|         /* Helpers. */
 | |
|         void CacheValues() {
 | |
|             std::scoped_lock lk(g_lock);
 | |
| 
 | |
|             if (g_has_cached) {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             /* Retrieve and cache values. */
 | |
|             {
 | |
| 
 | |
|                 alignas(os::MemoryPageSize) std::byte path_storage[2 * (MaxDirLen + 1)];
 | |
| 
 | |
|                 struct {
 | |
|                     char file_path[MaxDirLen + 1];
 | |
|                     char nintendo_path[MaxDirLen + 1];
 | |
|                 } *paths = reinterpret_cast<decltype(paths)>(std::addressof(path_storage));
 | |
| 
 | |
|                 /* Retrieve paths from secure monitor. */
 | |
|                 AMS_ABORT_UNLESS(spl::smc::AtmosphereGetEmummcConfig(std::addressof(g_exo_config), paths, 0) == spl::smc::Result::Success);
 | |
| 
 | |
|                 const Storage storage = static_cast<Storage>(g_exo_config.base_cfg.type);
 | |
|                 g_is_emummc = g_exo_config.base_cfg.magic == StorageMagic && storage != Storage_Emmc;
 | |
| 
 | |
|                 /* Format paths. */
 | |
|                 {
 | |
|                     char tmp_path[MaxDirLen + 1];
 | |
| 
 | |
|                     /* Format paths. */
 | |
|                     if (storage == Storage_SdFile) {
 | |
|                         util::TSNPrintf(tmp_path, sizeof(tmp_path), "/%s", paths->file_path);
 | |
|                         R_ABORT_UNLESS(fs::PathFormatter::Normalize(g_exo_config.file_cfg.path, sizeof(g_exo_config.file_cfg.path), tmp_path, std::strlen(tmp_path) + 1, fs::PathFlags{}));
 | |
|                     }
 | |
| 
 | |
|                     util::TSNPrintf(tmp_path, sizeof(tmp_path), "/%s", paths->nintendo_path);
 | |
|                     R_ABORT_UNLESS(fs::PathFormatter::Normalize(g_exo_config.emu_dir_path, sizeof(g_exo_config.emu_dir_path), tmp_path, std::strlen(tmp_path) + 1, fs::PathFlags{}));
 | |
| 
 | |
|                     /* If we're emummc, implement default nintendo redirection path. */
 | |
|                     if (g_is_emummc && std::strcmp(g_exo_config.emu_dir_path, "/") == 0) {
 | |
|                         util::TSNPrintf(tmp_path, sizeof(tmp_path), "/emummc/Nintendo_%04x", g_exo_config.base_cfg.id);
 | |
|                         R_ABORT_UNLESS(fs::PathFormatter::Normalize(g_exo_config.emu_dir_path, sizeof(g_exo_config.emu_dir_path), tmp_path, std::strlen(tmp_path) + 1, fs::PathFlags{}));
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             g_has_cached = true;
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /* Get whether emummc is active. */
 | |
|     bool IsActive() {
 | |
|         CacheValues();
 | |
|         return g_is_emummc;
 | |
|     }
 | |
| 
 | |
|     /* Get the active emummc id. */
 | |
|     u32 GetActiveId() {
 | |
|         CacheValues();
 | |
|         return g_exo_config.base_cfg.id;
 | |
|     }
 | |
| 
 | |
|     /* Get Nintendo redirection path. */
 | |
|     const char *GetNintendoDirPath() {
 | |
|         CacheValues();
 | |
|         if (!g_is_emummc) {
 | |
|             return nullptr;
 | |
|         }
 | |
|         return g_exo_config.emu_dir_path;
 | |
|     }
 | |
| 
 | |
|     /* Get Emummc folderpath, NULL if not file-based. */
 | |
|     const char *GetFilePath() {
 | |
|         CacheValues();
 | |
|         if (!g_is_emummc || g_exo_config.base_cfg.type != Storage_SdFile) {
 | |
|             return nullptr;
 | |
|         }
 | |
|         return g_exo_config.file_cfg.path;
 | |
|     }
 | |
| 
 | |
| }
 |