| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- using LibHac;
- using LibHac.Common;
- using LibHac.Fs;
- using LibHac.Fs.Fsa;
- using LibHac.FsSrv;
- using LibHac.FsSystem;
- using LibHac.Spl;
- using Ryujinx.Common.Configuration;
- using Ryujinx.HLE.FileSystem.Content;
- using Ryujinx.HLE.HOS;
- using System;
- using System.IO;
- namespace Ryujinx.HLE.FileSystem
- {
- public class VirtualFileSystem : IDisposable
- {
- public const string NandPath = AppDataManager.DefaultNandDir;
- public const string SdCardPath = AppDataManager.DefaultSdcardDir;
- public static string SafeNandPath = Path.Combine(NandPath, "safe");
- public static string SystemNandPath = Path.Combine(NandPath, "system");
- public static string UserNandPath = Path.Combine(NandPath, "user");
-
- private static bool _isInitialized = false;
- public Keyset KeySet { get; private set; }
- public FileSystemServer FsServer { get; private set; }
- public FileSystemClient FsClient { get; private set; }
- public EmulatedGameCard GameCard { get; private set; }
- public EmulatedSdCard SdCard { get; private set; }
- public ModLoader ModLoader {get; private set;}
- private VirtualFileSystem()
- {
- Reload();
- ModLoader = new ModLoader(); // Should only be created once
- }
- public Stream RomFs { get; private set; }
- public void LoadRomFs(string fileName)
- {
- RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
- }
- public void SetRomFs(Stream romfsStream)
- {
- RomFs?.Close();
- RomFs = romfsStream;
- }
- public string GetFullPath(string basePath, string fileName)
- {
- if (fileName.StartsWith("//"))
- {
- fileName = fileName.Substring(2);
- }
- else if (fileName.StartsWith('/'))
- {
- fileName = fileName.Substring(1);
- }
- else
- {
- return null;
- }
- string fullPath = Path.GetFullPath(Path.Combine(basePath, fileName));
- if (!fullPath.StartsWith(GetBasePath()))
- {
- return null;
- }
- return fullPath;
- }
- internal string GetBasePath() => AppDataManager.BaseDirPath;
- internal string GetSdCardPath() => MakeFullPath(SdCardPath);
- public string GetNandPath() => MakeFullPath(NandPath);
- internal string GetSavePath(ServiceCtx context, SaveInfo saveInfo, bool isDirectory = true)
- {
- string saveUserPath = "";
- string baseSavePath = NandPath;
- ulong currentTitleId = saveInfo.TitleId;
- switch (saveInfo.SaveSpaceId)
- {
- case SaveSpaceId.NandUser: baseSavePath = UserNandPath; break;
- case SaveSpaceId.NandSystem: baseSavePath = SystemNandPath; break;
- case SaveSpaceId.SdCard: baseSavePath = Path.Combine(SdCardPath, "Nintendo"); break;
- }
- baseSavePath = Path.Combine(baseSavePath, "save");
- if (saveInfo.TitleId == 0 && saveInfo.SaveDataType == SaveDataType.SaveData)
- {
- currentTitleId = context.Process.TitleId;
- }
- if (saveInfo.SaveSpaceId == SaveSpaceId.NandUser)
- {
- saveUserPath = saveInfo.UserId.IsNull ? "savecommon" : saveInfo.UserId.ToString();
- }
- string savePath = Path.Combine(baseSavePath,
- saveInfo.SaveId.ToString("x16"),
- saveUserPath,
- saveInfo.SaveDataType == SaveDataType.SaveData ? currentTitleId.ToString("x16") : string.Empty);
- return MakeFullPath(savePath, isDirectory);
- }
- public string GetFullPartitionPath(string partitionPath)
- {
- return MakeFullPath(partitionPath);
- }
- public string SwitchPathToSystemPath(string switchPath)
- {
- string[] parts = switchPath.Split(":");
- if (parts.Length != 2)
- {
- return null;
- }
- return GetFullPath(MakeFullPath(parts[0]), parts[1]);
- }
- public string SystemPathToSwitchPath(string systemPath)
- {
- string baseSystemPath = GetBasePath() + Path.DirectorySeparatorChar;
- if (systemPath.StartsWith(baseSystemPath))
- {
- string rawPath = systemPath.Replace(baseSystemPath, "");
- int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar);
- if (firstSeparatorOffset == -1)
- {
- return $"{rawPath}:/";
- }
- string basePath = rawPath.Substring(0, firstSeparatorOffset);
- string fileName = rawPath.Substring(firstSeparatorOffset + 1);
- return $"{basePath}:/{fileName}";
- }
- return null;
- }
- private string MakeFullPath(string path, bool isDirectory = true)
- {
- // Handles Common Switch Content Paths
- switch (path)
- {
- case ContentPath.SdCard:
- case "@Sdcard":
- path = SdCardPath;
- break;
- case ContentPath.User:
- path = UserNandPath;
- break;
- case ContentPath.System:
- path = SystemNandPath;
- break;
- case ContentPath.SdCardContent:
- path = Path.Combine(SdCardPath, "Nintendo", "Contents");
- break;
- case ContentPath.UserContent:
- path = Path.Combine(UserNandPath, "Contents");
- break;
- case ContentPath.SystemContent:
- path = Path.Combine(SystemNandPath, "Contents");
- break;
- }
- string fullPath = Path.Combine(GetBasePath(), path);
- if (isDirectory)
- {
- if (!Directory.Exists(fullPath))
- {
- Directory.CreateDirectory(fullPath);
- }
- }
- return fullPath;
- }
- public DriveInfo GetDrive()
- {
- return new DriveInfo(Path.GetPathRoot(GetBasePath()));
- }
- public void Reload()
- {
- ReloadKeySet();
- LocalFileSystem serverBaseFs = new LocalFileSystem(GetBasePath());
- DefaultFsServerObjects fsServerObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(serverBaseFs, KeySet);
- GameCard = fsServerObjects.GameCard;
- SdCard = fsServerObjects.SdCard;
- SdCard.SetSdCardInsertionStatus(true);
- FileSystemServerConfig fsServerConfig = new FileSystemServerConfig
- {
- FsCreators = fsServerObjects.FsCreators,
- DeviceOperator = fsServerObjects.DeviceOperator,
- ExternalKeySet = KeySet.ExternalKeySet
- };
- FsServer = new FileSystemServer(fsServerConfig);
- FsClient = FsServer.CreateFileSystemClient();
- }
- private void ReloadKeySet()
- {
- string keyFile = null;
- string titleKeyFile = null;
- string consoleKeyFile = null;
- if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile)
- {
- LoadSetAtPath(AppDataManager.KeysDirPathUser);
- }
- LoadSetAtPath(AppDataManager.KeysDirPath);
- void LoadSetAtPath(string basePath)
- {
- string localKeyFile = Path.Combine(basePath, "prod.keys");
- string localTitleKeyFile = Path.Combine(basePath, "title.keys");
- string localConsoleKeyFile = Path.Combine(basePath, "console.keys");
- if (File.Exists(localKeyFile))
- {
- keyFile = localKeyFile;
- }
- if (File.Exists(localTitleKeyFile))
- {
- titleKeyFile = localTitleKeyFile;
- }
- if (File.Exists(localConsoleKeyFile))
- {
- consoleKeyFile = localConsoleKeyFile;
- }
- }
- KeySet = ExternalKeyReader.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile);
- }
- public void ImportTickets(IFileSystem fs)
- {
- foreach (DirectoryEntryEx ticketEntry in fs.EnumerateEntries("/", "*.tik"))
- {
- Result result = fs.OpenFile(out IFile ticketFile, ticketEntry.FullPath.ToU8Span(), OpenMode.Read);
- if (result.IsSuccess())
- {
- Ticket ticket = new Ticket(ticketFile.AsStream());
- if (ticket.TitleKeyType == TitleKeyType.Common)
- {
- KeySet.ExternalKeySet.Add(new RightsId(ticket.RightsId), new AccessKey(ticket.GetTitleKey(KeySet)));
- }
- }
- }
- }
- public void Unload()
- {
- RomFs?.Dispose();
- }
- public void Dispose()
- {
- Dispose(true);
- }
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- Unload();
- }
- }
- public static VirtualFileSystem CreateInstance()
- {
- if (_isInitialized)
- {
- throw new InvalidOperationException($"VirtualFileSystem can only be instantiated once!");
- }
- _isInitialized = true;
- return new VirtualFileSystem();
- }
- }
- }
|