VirtualFileSystem.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. using Ryujinx.HLE.FileSystem.Content;
  2. using Ryujinx.HLE.HOS;
  3. using System;
  4. using System.IO;
  5. namespace Ryujinx.HLE.FileSystem
  6. {
  7. public class VirtualFileSystem : IDisposable
  8. {
  9. public const string BasePath = "Ryujinx";
  10. public const string NandPath = "bis";
  11. public const string SdCardPath = "sdcard";
  12. public const string SystemPath = "system";
  13. public static string SafeNandPath = Path.Combine(NandPath, "safe");
  14. public static string SystemNandPath = Path.Combine(NandPath, "system");
  15. public static string UserNandPath = Path.Combine(NandPath, "user");
  16. public Stream RomFs { get; private set; }
  17. public void LoadRomFs(string fileName)
  18. {
  19. RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
  20. }
  21. public void SetRomFs(Stream romfsStream)
  22. {
  23. RomFs?.Close();
  24. RomFs = romfsStream;
  25. }
  26. public string GetFullPath(string basePath, string fileName)
  27. {
  28. if (fileName.StartsWith("//"))
  29. {
  30. fileName = fileName.Substring(2);
  31. }
  32. else if (fileName.StartsWith('/'))
  33. {
  34. fileName = fileName.Substring(1);
  35. }
  36. else
  37. {
  38. return null;
  39. }
  40. string fullPath = Path.GetFullPath(Path.Combine(basePath, fileName));
  41. if (!fullPath.StartsWith(GetBasePath()))
  42. {
  43. return null;
  44. }
  45. return fullPath;
  46. }
  47. public string GetSdCardPath() => MakeFullPath(SdCardPath);
  48. public string GetNandPath() => MakeFullPath(NandPath);
  49. public string GetSystemPath() => MakeFullPath(SystemPath);
  50. internal string GetSavePath(ServiceCtx context, SaveInfo saveInfo, bool isDirectory = true)
  51. {
  52. string saveUserPath = "";
  53. string baseSavePath = NandPath;
  54. ulong currentTitleId = saveInfo.TitleId;
  55. switch (saveInfo.SaveSpaceId)
  56. {
  57. case SaveSpaceId.NandUser: baseSavePath = UserNandPath; break;
  58. case SaveSpaceId.NandSystem: baseSavePath = SystemNandPath; break;
  59. case SaveSpaceId.SdCard: baseSavePath = Path.Combine(SdCardPath, "Nintendo"); break;
  60. }
  61. baseSavePath = Path.Combine(baseSavePath, "save");
  62. if (saveInfo.TitleId == 0 && saveInfo.SaveDataType == SaveDataType.SaveData)
  63. {
  64. currentTitleId = context.Process.TitleId;
  65. }
  66. if (saveInfo.SaveSpaceId == SaveSpaceId.NandUser)
  67. {
  68. saveUserPath = saveInfo.UserId.IsNull ? "savecommon" : saveInfo.UserId.ToString();
  69. }
  70. string savePath = Path.Combine(baseSavePath,
  71. saveInfo.SaveId.ToString("x16"),
  72. saveUserPath,
  73. saveInfo.SaveDataType == SaveDataType.SaveData ? currentTitleId.ToString("x16") : string.Empty);
  74. return MakeFullPath(savePath, isDirectory);
  75. }
  76. public string GetFullPartitionPath(string partitionPath)
  77. {
  78. return MakeFullPath(partitionPath);
  79. }
  80. public string SwitchPathToSystemPath(string switchPath)
  81. {
  82. string[] parts = switchPath.Split(":");
  83. if (parts.Length != 2)
  84. {
  85. return null;
  86. }
  87. return GetFullPath(MakeFullPath(parts[0]), parts[1]);
  88. }
  89. public string SystemPathToSwitchPath(string systemPath)
  90. {
  91. string baseSystemPath = GetBasePath() + Path.DirectorySeparatorChar;
  92. if (systemPath.StartsWith(baseSystemPath))
  93. {
  94. string rawPath = systemPath.Replace(baseSystemPath, "");
  95. int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar);
  96. if (firstSeparatorOffset == -1)
  97. {
  98. return $"{rawPath}:/";
  99. }
  100. string basePath = rawPath.Substring(0, firstSeparatorOffset);
  101. string fileName = rawPath.Substring(firstSeparatorOffset + 1);
  102. return $"{basePath}:/{fileName}";
  103. }
  104. return null;
  105. }
  106. private string MakeFullPath(string path, bool isDirectory = true)
  107. {
  108. // Handles Common Switch Content Paths
  109. switch (path)
  110. {
  111. case ContentPath.SdCard:
  112. case "@Sdcard":
  113. path = SdCardPath;
  114. break;
  115. case ContentPath.User:
  116. path = UserNandPath;
  117. break;
  118. case ContentPath.System:
  119. path = SystemNandPath;
  120. break;
  121. case ContentPath.SdCardContent:
  122. path = Path.Combine(SdCardPath, "Nintendo", "Contents");
  123. break;
  124. case ContentPath.UserContent:
  125. path = Path.Combine(UserNandPath, "Contents");
  126. break;
  127. case ContentPath.SystemContent:
  128. path = Path.Combine(SystemNandPath, "Contents");
  129. break;
  130. }
  131. string fullPath = Path.Combine(GetBasePath(), path);
  132. if (isDirectory)
  133. {
  134. if (!Directory.Exists(fullPath))
  135. {
  136. Directory.CreateDirectory(fullPath);
  137. }
  138. }
  139. return fullPath;
  140. }
  141. public DriveInfo GetDrive()
  142. {
  143. return new DriveInfo(Path.GetPathRoot(GetBasePath()));
  144. }
  145. public string GetBasePath()
  146. {
  147. string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
  148. return Path.Combine(appDataPath, BasePath);
  149. }
  150. public void Dispose()
  151. {
  152. Dispose(true);
  153. }
  154. protected virtual void Dispose(bool disposing)
  155. {
  156. if (disposing)
  157. {
  158. RomFs?.Dispose();
  159. }
  160. }
  161. }
  162. }