diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index eaf4b4b6..c888c167 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -285,7 +285,7 @@ namespace LibHac.FsService SaveDataAttribute indexerKey = attribute; - if (attribute.SaveDataId != 0 || attribute.UserId == UserId.Zero) + if (attribute.SaveDataId != 0 && attribute.UserId == UserId.Zero) { saveDataId = attribute.SaveDataId; @@ -486,7 +486,8 @@ namespace LibHac.FsService using SaveDataIndexerReader reader = tmpReader; if (rc.IsFailure()) return rc; - reader.Indexer.Get(out SaveDataIndexerValue indexerValue, ref indexerKey); + rc = reader.Indexer.Get(out SaveDataIndexerValue indexerValue, ref indexerKey); + if (rc.IsFailure()) return rc; SaveDataSpaceId indexerSpaceId = GetSpaceIdForIndexer(spaceId); diff --git a/src/LibHac/FsService/SaveDataIndexerLite.cs b/src/LibHac/FsService/SaveDataIndexerLite.cs new file mode 100644 index 00000000..c0e69590 --- /dev/null +++ b/src/LibHac/FsService/SaveDataIndexerLite.cs @@ -0,0 +1,224 @@ +using System; +using System.Runtime.InteropServices; +using LibHac.Fs; + +namespace LibHac.FsService +{ + public class SaveDataIndexerLite : ISaveDataIndexer + { + private object Locker { get; } = new object(); + private ulong CurrentSaveDataId { get; set; } = 0x4000000000000000; + private bool IsKeyValueSet { get; set; } + + private SaveDataAttribute _key; + private SaveDataIndexerValue _value; + + public Result Commit() + { + return Result.Success; + } + + public Result Add(out ulong saveDataId, ref SaveDataAttribute key) + { + lock (Locker) + { + if (IsKeyValueSet && _key.Equals(key)) + { + saveDataId = default; + return ResultFs.SaveDataPathAlreadyExists.Log(); + } + + _key = key; + IsKeyValueSet = true; + + _value = new SaveDataIndexerValue { SaveDataId = CurrentSaveDataId }; + saveDataId = CurrentSaveDataId; + CurrentSaveDataId++; + + return Result.Success; + } + } + + public Result Get(out SaveDataIndexerValue value, ref SaveDataAttribute key) + { + lock (Locker) + { + if (IsKeyValueSet && _key.Equals(key)) + { + value = _value; + return Result.Success; + } + + value = default; + return ResultFs.TargetNotFound.Log(); + } + } + + public Result AddSystemSaveData(ref SaveDataAttribute key) + { + lock (Locker) + { + if (IsKeyValueSet && _key.Equals(key)) + { + return ResultFs.SaveDataPathAlreadyExists.Log(); + } + + _key = key; + IsKeyValueSet = true; + + _value = new SaveDataIndexerValue(); + + return Result.Success; + } + } + + public bool IsFull() + { + return false; + } + + public Result Delete(ulong saveDataId) + { + lock (Locker) + { + if (IsKeyValueSet && _value.SaveDataId == saveDataId) + { + IsKeyValueSet = false; + return Result.Success; + } + + return ResultFs.TargetNotFound.Log(); + } + } + + public Result SetSpaceId(ulong saveDataId, SaveDataSpaceId spaceId) + { + lock (Locker) + { + if (IsKeyValueSet && _value.SaveDataId == saveDataId) + { + _value.SpaceId = spaceId; + return Result.Success; + } + + return ResultFs.TargetNotFound.Log(); + } + } + + public Result SetSize(ulong saveDataId, long size) + { + // Nintendo doesn't lock in this function for some reason + lock (Locker) + { + if (IsKeyValueSet && _value.SaveDataId == saveDataId) + { + _value.Size = size; + return Result.Success; + } + + return ResultFs.TargetNotFound.Log(); + } + } + + public Result SetState(ulong saveDataId, SaveDataState state) + { + // Nintendo doesn't lock in this function for some reason + lock (Locker) + { + if (IsKeyValueSet && _value.SaveDataId == saveDataId) + { + _value.State = state; + return Result.Success; + } + + return ResultFs.TargetNotFound.Log(); + } + } + + public Result GetKey(out SaveDataAttribute key, ulong saveDataId) + { + lock (Locker) + { + if (IsKeyValueSet && _value.SaveDataId == saveDataId) + { + key = _key; + return Result.Success; + } + + key = default; + return ResultFs.TargetNotFound.Log(); + } + } + + public Result GetBySaveDataId(out SaveDataIndexerValue value, ulong saveDataId) + { + lock (Locker) + { + if (IsKeyValueSet && _value.SaveDataId == saveDataId) + { + value = _value; + return Result.Success; + } + + value = default; + return ResultFs.TargetNotFound.Log(); + } + } + + public int GetCount() + { + return 1; + } + + public Result OpenSaveDataInfoReader(out ISaveDataInfoReader infoReader) + { + if (IsKeyValueSet) + { + infoReader = new SaveDataIndexerLiteInfoReader(ref _key, ref _value); + } + else + { + infoReader = new SaveDataIndexerLiteInfoReader(); + } + + return Result.Success; + } + + private class SaveDataIndexerLiteInfoReader : ISaveDataInfoReader + { + private bool _finishedIterating; + private SaveDataInfo _info; + + public SaveDataIndexerLiteInfoReader() + { + _finishedIterating = true; + } + + public SaveDataIndexerLiteInfoReader(ref SaveDataAttribute key, ref SaveDataIndexerValue value) + { + SaveDataIndexer.GetSaveDataInfo(out _info, ref key, ref value); + } + + public Result ReadSaveDataInfo(out long readCount, Span saveDataInfoBuffer) + { + Span outInfo = MemoryMarshal.Cast(saveDataInfoBuffer); + + // Nintendo doesn't check if the buffer is too small here + if (_finishedIterating || outInfo.IsEmpty) + { + readCount = 0; + } + else + { + outInfo[0] = _info; + readCount = 1; + _finishedIterating = true; + } + + return Result.Success; + } + + public void Dispose() { } + } + } +} diff --git a/src/LibHac/FsService/SaveDataIndexerManager.cs b/src/LibHac/FsService/SaveDataIndexerManager.cs index 2a648341..41c7bd3b 100644 --- a/src/LibHac/FsService/SaveDataIndexerManager.cs +++ b/src/LibHac/FsService/SaveDataIndexerManager.cs @@ -1,5 +1,4 @@ -using System; -using System.Threading; +using System.Threading; using LibHac.Fs; namespace LibHac.FsService @@ -11,6 +10,7 @@ namespace LibHac.FsService private IndexerHolder _bisIndexer = new IndexerHolder(new object()); private IndexerHolder _sdCardIndexer = new IndexerHolder(new object()); + private IndexerHolder _tempIndexer = new IndexerHolder(new object()); private IndexerHolder _safeIndexer = new IndexerHolder(new object()); private IndexerHolder _properSystemIndexer = new IndexerHolder(new object()); @@ -51,7 +51,15 @@ namespace LibHac.FsService return Result.Success; case SaveDataSpaceId.Temporary: - throw new NotImplementedException(); + Monitor.Enter(_tempIndexer.Locker); + + if (!_tempIndexer.IsInitialized) + { + _tempIndexer.Indexer = new SaveDataIndexerLite(); + } + + reader = new SaveDataIndexerReader(_tempIndexer.Indexer, _tempIndexer.Locker); + return Result.Success; case SaveDataSpaceId.ProperSystem: Monitor.Enter(_safeIndexer.Locker);