diff --git a/src/LibHac/Fs/GameCard.cs b/src/LibHac/Fs/GameCard.cs index 70680e4a..7b2058b7 100644 --- a/src/LibHac/Fs/GameCard.cs +++ b/src/LibHac/Fs/GameCard.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Common; using LibHac.FsService; namespace LibHac.Fs @@ -13,6 +14,22 @@ namespace LibHac.Fs return fsProxy.OpenGameCardStorage(out storage, handle, partitionType); } + public static Result MountGameCardPartition(this FileSystemClient fs, U8Span mountName, GameCardHandle handle, + GameCardPartition partitionId) + { + Result rc = MountHelpers.CheckMountNameAcceptingReservedMountName(mountName); + if (rc.IsFailure()) return rc; + + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + rc = fsProxy.OpenGameCardFileSystem(out IFileSystem cardFs, handle, partitionId); + if (rc.IsFailure()) return rc; + + var mountNameGenerator = new GameCardCommonMountNameGenerator(handle, partitionId); + + return fs.Register(mountName, cardFs, mountNameGenerator); + } + public static Result GetGameCardHandle(this FileSystemClient fs, out GameCardHandle handle) { handle = default; @@ -57,6 +74,40 @@ namespace LibHac.Fs { return (long)page << 9; } + + private class GameCardCommonMountNameGenerator : ICommonMountNameGenerator + { + private GameCardHandle Handle { get; } + private GameCardPartition PartitionId { get; } + + public GameCardCommonMountNameGenerator(GameCardHandle handle, GameCardPartition partitionId) + { + Handle = handle; + PartitionId = partitionId; + } + + public Result Generate(Span nameBuffer) + { + char letter = GetPartitionMountLetter(PartitionId); + + string mountName = $"@Gc{letter}{Handle.Value:x8}"; + new U8Span(mountName).Value.CopyTo(nameBuffer); + + return Result.Success; + } + + private static char GetPartitionMountLetter(GameCardPartition partition) + { + switch (partition) + { + case GameCardPartition.Update: return 'U'; + case GameCardPartition.Normal: return 'N'; + case GameCardPartition.Secure: return 'S'; + default: + throw new ArgumentOutOfRangeException(nameof(partition), partition, null); + } + } + } } public enum GameCardSize diff --git a/src/LibHac/FsService/Creators/EmulatedGameCardFsCreator.cs b/src/LibHac/FsService/Creators/EmulatedGameCardFsCreator.cs new file mode 100644 index 00000000..f5fc1f71 --- /dev/null +++ b/src/LibHac/FsService/Creators/EmulatedGameCardFsCreator.cs @@ -0,0 +1,34 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class EmulatedGameCardFsCreator : IGameCardFileSystemCreator + { + // ReSharper disable once UnusedAutoPropertyAccessor.Local + private EmulatedGameCardStorageCreator StorageCreator { get; } + private EmulatedGameCard GameCard { get; } + + public EmulatedGameCardFsCreator(EmulatedGameCardStorageCreator storageCreator, EmulatedGameCard gameCard) + { + StorageCreator = storageCreator; + GameCard = gameCard; + } + public Result Create(out IFileSystem fileSystem, GameCardHandle handle, GameCardPartition partitionType) + { + // Use the old xci code temporarily + + fileSystem = default; + + Result rc = GameCard.GetXci(out Xci xci, handle); + if (rc.IsFailure()) return rc; + + if (!xci.HasPartition((XciPartitionType)partitionType)) + { + return ResultFs.PartitionNotFound.Log(); + } + + fileSystem = xci.OpenPartition((XciPartitionType)partitionType); + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs index a0b73f52..96160f70 100644 --- a/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs @@ -3,7 +3,7 @@ using LibHac.Fs; namespace LibHac.FsService.Creators { - class EmulatedGameCardStorageCreator : IGameCardStorageCreator + public class EmulatedGameCardStorageCreator : IGameCardStorageCreator { private EmulatedGameCard GameCard { get; } diff --git a/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs index b27c6aff..8000510d 100644 --- a/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs @@ -35,6 +35,8 @@ namespace LibHac.FsService.Creators string path = Path ?? DefaultPath; + // Todo: Add ProxyFileSystem? + return Util.CreateSubFileSystem(out fileSystem, RootFileSystem, path, true); } diff --git a/src/LibHac/FsService/DefaultFsServerObjects.cs b/src/LibHac/FsService/DefaultFsServerObjects.cs index 9ea1f4c2..469757cf 100644 --- a/src/LibHac/FsService/DefaultFsServerObjects.cs +++ b/src/LibHac/FsService/DefaultFsServerObjects.cs @@ -14,9 +14,12 @@ namespace LibHac.FsService var creators = new FileSystemCreators(); var gameCard = new EmulatedGameCard(keyset); + var gcStorageCreator = new EmulatedGameCardStorageCreator(gameCard); + creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(keyset); - creators.GameCardStorageCreator = new EmulatedGameCardStorageCreator(gameCard); + creators.GameCardStorageCreator = gcStorageCreator; + creators.GameCardFileSystemCreator = new EmulatedGameCardFsCreator(gcStorageCreator, gameCard); creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keyset); creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem); creators.SdFileSystemCreator = new EmulatedSdFileSystemCreator(rootFileSystem); diff --git a/src/LibHac/FsService/EmulatedGameCard.cs b/src/LibHac/FsService/EmulatedGameCard.cs index 121fc03c..b54d20c3 100644 --- a/src/LibHac/FsService/EmulatedGameCard.cs +++ b/src/LibHac/FsService/EmulatedGameCard.cs @@ -1,6 +1,5 @@ using System; using LibHac.Fs; -using LibHac.FsSystem; namespace LibHac.FsService { @@ -9,6 +8,7 @@ namespace LibHac.FsService private IStorage CardImageStorage { get; set; } private int Handle { get; set; } private XciHeader CardHeader { get; set; } + private Xci CardImage { get; set; } private Keyset Keyset { get; set; } public EmulatedGameCard() { } @@ -38,7 +38,8 @@ namespace LibHac.FsService CardImageStorage = cardImageStorage; - CardHeader = new XciHeader(Keyset, cardImageStorage.AsStream()); + CardImage = new Xci(Keyset, cardImageStorage); + CardHeader = CardImage.Header; } public void RemoveGameCard() @@ -49,7 +50,17 @@ namespace LibHac.FsService Handle++; } } + + internal Result GetXci(out Xci xci, GameCardHandle handle) + { + xci = default; + if (IsGameCardHandleInvalid(handle)) return ResultFs.InvalidGameCardHandleOnRead.Log(); + if (!IsGameCardInserted()) return ResultFs.GameCardNotInserted.Log(); + + xci = CardImage; + return Result.Success; + } public Result Read(GameCardHandle handle, long offset, Span destination) { if (IsGameCardHandleInvalid(handle)) return ResultFs.InvalidGameCardHandleOnRead.Log(); diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index b16566ec..9b18e9e0 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -423,9 +423,12 @@ namespace LibHac.FsService return FsProxyCore.OpenCustomStorageFileSystem(out fileSystem, storageId); } - public Result OpenGameCardFileSystem(out IFileSystem fileSystem, GameCardHandle handle, GameCardPartition partitionId) + public Result OpenGameCardFileSystem(out IFileSystem fileSystem, GameCardHandle handle, + GameCardPartition partitionId) { - throw new NotImplementedException(); + // Missing permission check and FileSystemInterfaceAdapter + + return FsProxyCore.OpenGameCardFileSystem(out fileSystem, handle, partitionId); } public Result QuerySaveDataTotalSize(out long totalSize, long dataSize, long journalSize) diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index df691c0b..c53b32da 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -149,6 +149,12 @@ namespace LibHac.FsService } } + public Result OpenGameCardFileSystem(out IFileSystem fileSystem, GameCardHandle handle, + GameCardPartition partitionId) + { + return FsCreators.GameCardFileSystemCreator.Create(out fileSystem, handle, partitionId); + } + public Result RegisterExternalKey(ref RightsId rightsId, ref AccessKey externalKey) { return ExternalKeys.Add(rightsId, externalKey);