From 838bb18a09b4cd8d2264d7a5ce1b885d1760f7dc Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 27 Sep 2019 23:36:43 -0500 Subject: [PATCH] Add some savedata client functions --- src/LibHac/Fs/FileSystemClient.AccessLog.cs | 94 ++++++++++++ src/LibHac/Fs/SaveData.cs | 144 ++++++++++++++++++ ...aAttribute.cs => SaveDataAttributeKvdb.cs} | 10 +- src/LibHac/Fs/SaveDataStructs.cs | 10 +- src/LibHac/FsService/FileSystemProxy.cs | 24 +-- src/LibHac/FsService/IFileSystemProxy.cs | 18 +-- src/LibHac/FsSystem/Save/Header.cs | 3 +- 7 files changed, 274 insertions(+), 29 deletions(-) create mode 100644 src/LibHac/Fs/FileSystemClient.AccessLog.cs create mode 100644 src/LibHac/Fs/SaveData.cs rename src/LibHac/Fs/{SaveDataAttribute.cs => SaveDataAttributeKvdb.cs} (87%) diff --git a/src/LibHac/Fs/FileSystemClient.AccessLog.cs b/src/LibHac/Fs/FileSystemClient.AccessLog.cs new file mode 100644 index 00000000..926f4cff --- /dev/null +++ b/src/LibHac/Fs/FileSystemClient.AccessLog.cs @@ -0,0 +1,94 @@ +using System; +using LibHac.FsService; + +namespace LibHac.Fs +{ + public partial class FileSystemClient + { + private GlobalAccessLogMode GlobalAccessLogMode { get; set; } + private LocalAccessLogMode LocalAccessLogMode { get; set; } + private bool AccessLogInitialized { get; set; } + + private readonly object _accessLogInitLocker = new object(); + + public Result GetGlobalAccessLogMode(out GlobalAccessLogMode mode) + { + IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); + + return fsProxy.GetGlobalAccessLogMode(out mode); + } + + public Result SetGlobalAccessLogMode(GlobalAccessLogMode mode) + { + IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); + + return fsProxy.SetGlobalAccessLogMode(mode); + } + + public void SetLocalAccessLogMode(LocalAccessLogMode mode) + { + LocalAccessLogMode = mode; + } + + internal bool IsEnabledAccessLog(LocalAccessLogMode mode) + { + if (!LocalAccessLogMode.HasFlag(mode)) + { + return false; + } + + if (AccessLogInitialized) + { + return GlobalAccessLogMode != GlobalAccessLogMode.None; + } + + lock (_accessLogInitLocker) + { + if (!AccessLogInitialized) + { + IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); + + Result rc = fsProxy.GetGlobalAccessLogMode(out GlobalAccessLogMode globalMode); + GlobalAccessLogMode = globalMode; + + if (rc.IsFailure()) + { + throw new LibHacException("Abort"); + } + + if (GlobalAccessLogMode != GlobalAccessLogMode.None) + { + InitAccessLog(); + } + + AccessLogInitialized = true; + } + } + + return GlobalAccessLogMode != GlobalAccessLogMode.None; + } + + private void InitAccessLog() + { + + } + } + + [Flags] + public enum LocalAccessLogMode + { + None = 0, + Application = 1 << 0, + Internal = 1 << 1, + All = Application | Internal + } + + [Flags] + public enum GlobalAccessLogMode + { + None = 0, + Log = 1 << 0, + SdCard = 1 << 1, + All = Log | SdCard + } +} diff --git a/src/LibHac/Fs/SaveData.cs b/src/LibHac/Fs/SaveData.cs new file mode 100644 index 00000000..414ca00a --- /dev/null +++ b/src/LibHac/Fs/SaveData.cs @@ -0,0 +1,144 @@ +using System; +using LibHac.Common; +using LibHac.FsService; + +namespace LibHac.Fs +{ + public static class SaveData + { + public static Result MountSystemSaveData(this FileSystemClient fs, U8Span mountName, + SaveDataSpaceId spaceId, ulong saveDataId, UserId userId) + { + Result rc = MountHelpers.CheckMountName(mountName); + if (rc.IsFailure()) return rc; + + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + SaveDataAttribute attribute = default; + attribute.UserId = userId; + attribute.SaveDataId = saveDataId; + + rc = fsProxy.OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, spaceId, ref attribute); + if (rc.IsFailure()) return rc; + + return fs.Register(mountName, fileSystem); + } + + public static Result CreateSystemSaveData(this FileSystemClient fs, SaveDataSpaceId spaceId, ulong saveDataId, + UserId userId, ulong ownerId, long size, long journalSize, uint flags) + { + if (fs.IsEnabledAccessLog(LocalAccessLogMode.Internal)) + { + TimeSpan startTime = fs.Time.GetCurrent(); + + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + var attribute = new SaveDataAttribute + { + UserId = userId, + SaveDataId = saveDataId + }; + + var createInfo = new SaveDataCreateInfo + { + Size = size, + JournalSize = journalSize, + BlockSize = 0x4000, + OwnerId = ownerId, + Flags = flags, + SpaceId = spaceId + }; + + Result rc = fsProxy.CreateSaveDataFileSystemBySystemSaveDataId(ref attribute, ref createInfo); + + TimeSpan endTime = fs.Time.GetCurrent(); + + fs.OutputAccessLog(rc, startTime, endTime, + $", savedataspaceid: {spaceId}, savedataid: 0x{saveDataId:X}, userid: 0x{userId.Id.High:X16}{userId.Id.Low:X16}, save_data_owner_id: 0x{ownerId:X}, save_data_size: {size}, save_data_journal_size: {journalSize}, save_data_flags: 0x{flags:X8}"); + + return rc; + } + else + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + var attribute = new SaveDataAttribute + { + UserId = userId, + SaveDataId = saveDataId + }; + + var createInfo = new SaveDataCreateInfo + { + Size = size, + JournalSize = journalSize, + BlockSize = 0x4000, + OwnerId = ownerId, + Flags = flags, + SpaceId = spaceId + }; + + return fsProxy.CreateSaveDataFileSystemBySystemSaveDataId(ref attribute, ref createInfo); + } + } + + public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, UserId userId, + ulong ownerId, long size, long journalSize, uint flags) + { + return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, userId, ownerId, size, journalSize, flags); + } + + public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, UserId userId, long size, + long journalSize, uint flags) + { + return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, userId, 0, size, journalSize, flags); + } + + public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, ulong ownerId, long size, + long journalSize, uint flags) + { + return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, new UserId(0, 0), ownerId, size, journalSize, flags); + } + + public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, long size, + long journalSize, uint flags) + { + return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, new UserId(0, 0), 0, size, journalSize, flags); + } + + public static Result CreateSystemSaveData(this FileSystemClient fs, SaveDataSpaceId spaceId, ulong saveDataId, + ulong ownerId, long size, long journalSize, uint flags) + { + return CreateSystemSaveData(fs, spaceId, saveDataId, new UserId(0, 0), ownerId, size, journalSize, flags); + } + + public static Result DeleteSaveData(this FileSystemClient fs, ulong saveDataId) + { + if (fs.IsEnabledAccessLog(LocalAccessLogMode.Internal)) + { + TimeSpan startTime = fs.Time.GetCurrent(); + + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + Result result = fsProxy.DeleteSaveDataFileSystem(saveDataId); + + TimeSpan endTime = fs.Time.GetCurrent(); + + fs.OutputAccessLog(result, startTime, endTime, $", savedataid: 0x{saveDataId:X}"); + + return result; + } + else + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + return fsProxy.DeleteSaveDataFileSystem(saveDataId); + } + } + + public static Result DisableAutoSaveDataCreation(this FileSystemClient fsClient) + { + IFileSystemProxy fsProxy = fsClient.GetFileSystemProxyServiceObject(); + + return fsProxy.DisableAutoSaveDataCreation(); + } + } +} diff --git a/src/LibHac/Fs/SaveDataAttribute.cs b/src/LibHac/Fs/SaveDataAttributeKvdb.cs similarity index 87% rename from src/LibHac/Fs/SaveDataAttribute.cs rename to src/LibHac/Fs/SaveDataAttributeKvdb.cs index 3fd4614d..5588bdf2 100644 --- a/src/LibHac/Fs/SaveDataAttribute.cs +++ b/src/LibHac/Fs/SaveDataAttributeKvdb.cs @@ -5,7 +5,7 @@ using LibHac.Kvdb; namespace LibHac.Fs { - public class SaveDataAttribute : IComparable, IComparable, IEquatable, IExportable + public class SaveDataAttributeKvdb : IComparable, IComparable, IEquatable, IExportable { public ulong TitleId { get; private set; } public UserId UserId { get; private set; } @@ -44,7 +44,7 @@ namespace LibHac.Fs public void Freeze() => _isFrozen = true; - public bool Equals(SaveDataAttribute other) + public bool Equals(SaveDataAttributeKvdb other) { return other != null && TitleId == other.TitleId && UserId.Equals(other.UserId) && SaveId == other.SaveId && Type == other.Type && Rank == other.Rank && Index == other.Index; @@ -52,7 +52,7 @@ namespace LibHac.Fs public override bool Equals(object obj) { - return obj is SaveDataAttribute other && Equals(other); + return obj is SaveDataAttributeKvdb other && Equals(other); } public override int GetHashCode() @@ -71,7 +71,7 @@ namespace LibHac.Fs } } - public int CompareTo(SaveDataAttribute other) + public int CompareTo(SaveDataAttributeKvdb other) { int titleIdComparison = TitleId.CompareTo(other.TitleId); if (titleIdComparison != 0) return titleIdComparison; @@ -89,7 +89,7 @@ namespace LibHac.Fs public int CompareTo(object obj) { if (obj is null) return 1; - return obj is SaveDataAttribute other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(SaveDataAttribute)}"); + return obj is SaveDataAttributeKvdb other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(SaveDataAttributeKvdb)}"); } } } diff --git a/src/LibHac/Fs/SaveDataStructs.cs b/src/LibHac/Fs/SaveDataStructs.cs index adcd0569..581dc4cd 100644 --- a/src/LibHac/Fs/SaveDataStructs.cs +++ b/src/LibHac/Fs/SaveDataStructs.cs @@ -7,7 +7,7 @@ using LibHac.Ncm; namespace LibHac.Fs { [StructLayout(LayoutKind.Explicit, Size = 0x40)] - public struct SaveDataAttribute2 + public struct SaveDataAttribute { [FieldOffset(0x00)] public ulong TitleId; [FieldOffset(0x08)] public UserId UserId; @@ -78,6 +78,12 @@ namespace LibHac.Fs [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct SaveDataCreateInfo { - // Todo + [FieldOffset(0x00)] public long Size; + [FieldOffset(0x08)] public long JournalSize; + [FieldOffset(0x10)] public ulong BlockSize; + [FieldOffset(0x18)] public ulong OwnerId; + [FieldOffset(0x20)] public uint Flags; + [FieldOffset(0x24)] public SaveDataSpaceId SpaceId; + [FieldOffset(0x25)] public bool Field25; } } diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index cfa8c405..51fd4e0b 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -112,7 +112,7 @@ namespace LibHac.FsService throw new NotImplementedException(); } - public Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute) + public Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, ref SaveDataAttribute attribute) { throw new NotImplementedException(); } @@ -122,19 +122,19 @@ namespace LibHac.FsService throw new NotImplementedException(); } - public Result CreateSaveDataFileSystem(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo, + public Result CreateSaveDataFileSystem(ref SaveDataAttribute attribute, ref SaveDataCreateInfo createInfo, ref SaveMetaCreateInfo metaCreateInfo) { throw new NotImplementedException(); } - public Result CreateSaveDataFileSystemWithHashSalt(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo, + public Result CreateSaveDataFileSystemWithHashSalt(ref SaveDataAttribute attribute, ref SaveDataCreateInfo createInfo, ref SaveMetaCreateInfo metaCreateInfo, ref HashSalt hashSalt) { throw new NotImplementedException(); } - public Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo) + public Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute attribute, ref SaveDataCreateInfo createInfo) { throw new NotImplementedException(); } @@ -147,11 +147,11 @@ namespace LibHac.FsService private Result OpenSaveDataFileSystemImpl(out IFileSystem fileSystem, out ulong saveDataId, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData) { - bool hasFixedId = attribute.SaveId != 0 && attribute.UserId.Id == Id128.InvalidId; + bool hasFixedId = attribute.SaveDataId != 0 && attribute.UserId.Id == Id128.InvalidId; if (hasFixedId) { - saveDataId = attribute.SaveId; + saveDataId = attribute.SaveDataId; } else { @@ -194,7 +194,7 @@ namespace LibHac.FsService // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter fileSystem = default; - if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log(); + if (!IsSystemSaveDataId(attribute.SaveDataId)) return ResultFs.InvalidArgument.Log(); Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out _, spaceId, ref attribute, false, true); @@ -219,7 +219,7 @@ namespace LibHac.FsService } public Result ReadSaveDataFileSystemExtraDataBySaveDataAttribute(Span extraDataBuffer, SaveDataSpaceId spaceId, - ref SaveDataAttribute2 attribute) + ref SaveDataAttribute attribute) { throw new NotImplementedException(); } @@ -229,7 +229,7 @@ namespace LibHac.FsService throw new NotImplementedException(); } - public Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute(ref SaveDataAttribute2 attribute, SaveDataSpaceId spaceId, + public Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute(ref SaveDataAttribute attribute, SaveDataSpaceId spaceId, ReadOnlySpan extraDataBuffer, ReadOnlySpan maskBuffer) { throw new NotImplementedException(); @@ -352,7 +352,7 @@ namespace LibHac.FsService throw new NotImplementedException(); } - public Result OpenSaveDataMetaFile(out IFile file, SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute, + public Result OpenSaveDataMetaFile(out IFile file, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute, SaveMetaType type) { throw new NotImplementedException(); @@ -520,12 +520,12 @@ namespace LibHac.FsService return Result.Success; } - public Result SetGlobalAccessLogMode(int mode) + public Result SetGlobalAccessLogMode(GlobalAccessLogMode mode) { throw new NotImplementedException(); } - public Result GetGlobalAccessLogMode(out int mode) + public Result GetGlobalAccessLogMode(out GlobalAccessLogMode mode) { throw new NotImplementedException(); } diff --git a/src/LibHac/FsService/IFileSystemProxy.cs b/src/LibHac/FsService/IFileSystemProxy.cs index 2b5791ca..525b1f33 100644 --- a/src/LibHac/FsService/IFileSystemProxy.cs +++ b/src/LibHac/FsService/IFileSystemProxy.cs @@ -21,19 +21,19 @@ namespace LibHac.FsService Result OpenSdCardFileSystem(out IFileSystem fileSystem); Result FormatSdCardFileSystem(); Result DeleteSaveDataFileSystem(ulong saveDataId); - Result CreateSaveDataFileSystem(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo, ref SaveMetaCreateInfo metaCreateInfo); - Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo); + Result CreateSaveDataFileSystem(ref SaveDataAttribute attribute, ref SaveDataCreateInfo createInfo, ref SaveMetaCreateInfo metaCreateInfo); + Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute attribute, ref SaveDataCreateInfo createInfo); Result RegisterSaveDataFileSystemAtomicDeletion(ReadOnlySpan saveDataIds); Result DeleteSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId); Result FormatSdCardDryRun(); Result IsExFatSupported(out bool isSupported); - Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute); + Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, ref SaveDataAttribute attribute); Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId); Result OpenGameCardFileSystem(out IFileSystem fileSystem, GameCardHandle handle, GameCardPartition partitionId); Result ExtendSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long dataSize, long journalSize); Result DeleteCacheStorage(short index); Result GetCacheStorageSize(out long dataSize, out long journalSize, short index); - Result CreateSaveDataFileSystemWithHashSalt(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo, ref SaveMetaCreateInfo metaCreateInfo, ref HashSalt hashSalt); + Result CreateSaveDataFileSystemWithHashSalt(ref SaveDataAttribute attribute, ref SaveDataCreateInfo createInfo, ref SaveMetaCreateInfo metaCreateInfo, ref HashSalt hashSalt); Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute); Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute); Result OpenReadOnlySaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute); @@ -48,9 +48,9 @@ namespace LibHac.FsService Result WriteSaveDataFileSystemExtraDataWithMask(ulong saveDataId, SaveDataSpaceId spaceId, ReadOnlySpan extraDataBuffer, ReadOnlySpan maskBuffer); Result FindSaveDataWithFilter(out long count, Span saveDataInfoBuffer, SaveDataSpaceId spaceId, ref SaveDataFilter filter); Result OpenSaveDataInfoReaderWithFilter(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId, ref SaveDataFilter filter); - Result ReadSaveDataFileSystemExtraDataBySaveDataAttribute(Span extraDataBuffer, SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute); - Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute(ref SaveDataAttribute2 attribute, SaveDataSpaceId spaceId, ReadOnlySpan extraDataBuffer, ReadOnlySpan maskBuffer); - Result OpenSaveDataMetaFile(out IFile file, SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute, SaveMetaType type); + Result ReadSaveDataFileSystemExtraDataBySaveDataAttribute(Span extraDataBuffer, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute); + Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute(ref SaveDataAttribute attribute, SaveDataSpaceId spaceId, ReadOnlySpan extraDataBuffer, ReadOnlySpan maskBuffer); + Result OpenSaveDataMetaFile(out IFile file, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute, SaveMetaType type); Result ListAccessibleSaveDataOwnerId(out int readCount, Span idBuffer, TitleId programId, int startIndex, int bufferIdCount); Result OpenImageDirectoryFileSystem(out IFileSystem fileSystem, ImageDirectoryId dirId); @@ -90,8 +90,8 @@ namespace LibHac.FsService Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); Result SetSaveDataRootPath(ref FsPath path); Result DisableAutoSaveDataCreation(); - Result SetGlobalAccessLogMode(int mode); - Result GetGlobalAccessLogMode(out int mode); + Result SetGlobalAccessLogMode(GlobalAccessLogMode mode); + Result GetGlobalAccessLogMode(out GlobalAccessLogMode mode); Result OutputAccessLogToSdCard(U8Span logString); Result RegisterUpdatePartition(); Result OpenRegisteredUpdatePartition(out IFileSystem fileSystem); diff --git a/src/LibHac/FsSystem/Save/Header.cs b/src/LibHac/FsSystem/Save/Header.cs index 98a98f4f..39fb32cb 100644 --- a/src/LibHac/FsSystem/Save/Header.cs +++ b/src/LibHac/FsSystem/Save/Header.cs @@ -288,6 +288,7 @@ namespace LibHac.FsSystem.Save BcatDeliveryCacheStorage = 2, DeviceSaveData = 3, TemporaryStorage = 4, - CacheStorage = 5 + CacheStorage = 5, + BcatSystemStorage = 6 } }