From 69658ae08e718c0a40bfe79a2b262bc133c1d1be Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 30 Jun 2019 23:49:52 -0500 Subject: [PATCH] Add result ranges and convert savedata results to external results --- src/LibHac/Fs/Accessors/MountTable.cs | 8 +- src/LibHac/Fs/FileSystemManager.cs | 6 +- src/LibHac/Fs/PathTools.cs | 4 +- src/LibHac/Fs/ResultFs.cs | 42 +++++++- src/LibHac/Fs/ResultRangeFs.cs | 21 ++++ src/LibHac/Fs/RomFs/RomFsFileSystem.cs | 2 +- src/LibHac/Fs/Save/AllocationTable.cs | 10 ++ src/LibHac/Fs/Save/SaveResults.cs | 127 +++++++++++++++++++++++++ src/LibHac/Kvdb/ImkvdbReader.cs | 19 ++-- src/LibHac/Kvdb/KeyValueDatabase.cs | 13 +-- src/LibHac/Kvdb/ResultKvdb.cs | 13 +++ src/LibHac/Kvdb/ResultsKvdb.cs | 13 --- src/LibHac/Result.cs | 32 ++++++- src/LibHac/ResultRange.cs | 21 ++++ 14 files changed, 278 insertions(+), 53 deletions(-) create mode 100644 src/LibHac/Fs/ResultRangeFs.cs create mode 100644 src/LibHac/Fs/Save/SaveResults.cs create mode 100644 src/LibHac/Kvdb/ResultKvdb.cs delete mode 100644 src/LibHac/Kvdb/ResultsKvdb.cs create mode 100644 src/LibHac/ResultRange.cs diff --git a/src/LibHac/Fs/Accessors/MountTable.cs b/src/LibHac/Fs/Accessors/MountTable.cs index 8aacade7..ec9f94cb 100644 --- a/src/LibHac/Fs/Accessors/MountTable.cs +++ b/src/LibHac/Fs/Accessors/MountTable.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -using static LibHac.Results; - namespace LibHac.Fs.Accessors { public class MountTable @@ -23,7 +21,7 @@ namespace LibHac.Fs.Accessors Table.Add(mountName, fileSystem); - return ResultSuccess; + return Result.Success; } } @@ -36,7 +34,7 @@ namespace LibHac.Fs.Accessors return ResultFs.MountNameNotFound; } - return ResultSuccess; + return Result.Success; } } @@ -52,7 +50,7 @@ namespace LibHac.Fs.Accessors Table.Remove(name); fsAccessor.Close(); - return ResultSuccess; + return Result.Success; } } } diff --git a/src/LibHac/Fs/FileSystemManager.cs b/src/LibHac/Fs/FileSystemManager.cs index 566c99b5..9dd2ede5 100644 --- a/src/LibHac/Fs/FileSystemManager.cs +++ b/src/LibHac/Fs/FileSystemManager.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using LibHac.Fs.Accessors; -using static LibHac.Results; - namespace LibHac.Fs { public class FileSystemManager @@ -508,7 +506,7 @@ namespace LibHac.Fs result = MountTable.Find(mountName.ToString(), out fileSystem); if (result.IsFailure()) return result; - return ResultSuccess; + return Result.Success; } internal Result GetMountName(ReadOnlySpan path, out ReadOnlySpan mountName, out ReadOnlySpan subPath) @@ -544,7 +542,7 @@ namespace LibHac.Fs subPath = default; } - return ResultSuccess; + return Result.Success; } internal bool IsEnabledAccessLog() diff --git a/src/LibHac/Fs/PathTools.cs b/src/LibHac/Fs/PathTools.cs index 1aec4e7e..496d8eb5 100644 --- a/src/LibHac/Fs/PathTools.cs +++ b/src/LibHac/Fs/PathTools.cs @@ -2,8 +2,6 @@ using System.Diagnostics; using System.Runtime.CompilerServices; -using static LibHac.Results; - #if !NETFRAMEWORK using System.IO.Enumeration; #endif @@ -376,7 +374,7 @@ namespace LibHac.Fs if (path[i] == MountSeparator) { mountName = path.Substring(0, i); - return ResultSuccess; + return Result.Success; } } diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 69b4eb6a..5ddc6542 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -5,9 +5,15 @@ public const int ModuleFs = 2; public static Result PathNotFound => new Result(ModuleFs, 1); + public static Result PathAlreadyExists => new Result(ModuleFs, 2); + public static Result TargetLocked => new Result(ModuleFs, 7); + public static Result DirectoryNotEmpty => new Result(ModuleFs, 8); + public static Result InsufficientFreeSpace => new Result(ModuleFs, 30); public static Result MountNameAlreadyExists => new Result(ModuleFs, 60); public static Result NotImplemented => new Result(ModuleFs, 3001); + public static Result Result3002 => new Result(ModuleFs, 3002); + public static Result SaveDataPathAlreadyExists => new Result(ModuleFs, 3003); public static Result ValueOutOfRange => new Result(ModuleFs, 3005); public static Result AesXtsFileFileStorageAllocationError => new Result(ModuleFs, 3312); @@ -18,15 +24,33 @@ public static Result InvalidIndirectStorageSource => new Result(ModuleFs, 4023); + public static Result Result4302 => new Result(ModuleFs, 4302); public static Result InvalidSaveDataHeader => new Result(ModuleFs, 4315); + public static Result Result4362 => new Result(ModuleFs, 4362); + public static Result Result4363 => new Result(ModuleFs, 4363); + public static Result InvalidHashInSaveIvfc => new Result(ModuleFs, 4364); + public static Result SaveIvfcHashIsEmpty => new Result(ModuleFs, 4372); + public static Result InvalidHashInSaveIvfcTopLayer => new Result(ModuleFs, 4373); + + public static Result Result4402 => new Result(ModuleFs, 4402); + public static Result Result4427 => new Result(ModuleFs, 4427); + public static Result SaveDataAllocationTableCorrupted => new Result(ModuleFs, 4462); + public static Result SaveDataFileTableCorrupted => new Result(ModuleFs, 4463); + public static Result AllocationTableIteratedRangeEntry => new Result(ModuleFs, 4464); + + public static Result Result4602 => new Result(ModuleFs, 4602); + public static Result Result4603 => new Result(ModuleFs, 4603); public static Result InvalidHashInIvfc => new Result(ModuleFs, 4604); public static Result IvfcHashIsEmpty => new Result(ModuleFs, 4612); public static Result InvalidHashInIvfcTopLayer => new Result(ModuleFs, 4613); public static Result InvalidPartitionFileSystemMagic => new Result(ModuleFs, 4644); public static Result InvalidHashedPartitionFileSystemMagic => new Result(ModuleFs, 4645); + public static Result Result4662 => new Result(ModuleFs, 4662); - + public static Result SaveDataAllocationTableCorruptedInternal => new Result(ModuleFs, 4722); + public static Result SaveDataFileTableCorruptedInternal => new Result(ModuleFs, 4723); + public static Result AllocationTableIteratedRangeEntryInternal => new Result(ModuleFs, 4724); public static Result AesXtsFileHeaderTooShort => new Result(ModuleFs, 4742); public static Result AesXtsFileHeaderInvalidKeys => new Result(ModuleFs, 4743); public static Result AesXtsFileHeaderInvalidMagic => new Result(ModuleFs, 4744); @@ -35,7 +59,18 @@ public static Result AesXtsFileHeaderInvalidKeysInRenameFile => new Result(ModuleFs, 4747); public static Result AesXtsFileHeaderInvalidKeysInSetSize => new Result(ModuleFs, 4748); - public static Result InvalidInput => new Result(ModuleFs, 6001); + public static Result Result4812 => new Result(ModuleFs, 4812); + + public static Result PreconditionViolation => new Result(ModuleFs, 6000); + public static Result InvalidArgument => new Result(ModuleFs, 6001); + public static Result InvalidPath => new Result(ModuleFs, 6002); + public static Result TooLongPath => new Result(ModuleFs, 6003); + public static Result InvalidCharacter => new Result(ModuleFs, 6004); + public static Result InvalidPathFormat => new Result(ModuleFs, 6005); + public static Result DirectoryUnobtainable => new Result(ModuleFs, 6006); + public static Result NotNormalized => new Result(ModuleFs, 6007); + + public static Result PathNotFoundInSaveDataFileTable => new Result(ModuleFs, 6033); public static Result DifferentDestFileSystem => new Result(ModuleFs, 6034); public static Result InvalidOffset => new Result(ModuleFs, 6061); public static Result InvalidSize => new Result(ModuleFs, 6062); @@ -60,9 +95,10 @@ public static Result UnsupportedOperationModifyPartitionFileSystem => new Result(ModuleFs, 6374); public static Result UnsupportedOperationInPartitionFileSetSize => new Result(ModuleFs, 6376); + public static Result PermissionDenied => new Result(ModuleFs, 6400); public static Result WriteStateUnflushed => new Result(ModuleFs, 6454); public static Result WritableFileOpen => new Result(ModuleFs, 6457); - + public static Result AllocationTableInsufficientFreeBlocks => new Result(ModuleFs, 6707); diff --git a/src/LibHac/Fs/ResultRangeFs.cs b/src/LibHac/Fs/ResultRangeFs.cs new file mode 100644 index 00000000..f0289aeb --- /dev/null +++ b/src/LibHac/Fs/ResultRangeFs.cs @@ -0,0 +1,21 @@ +namespace LibHac.Fs +{ + public static class ResultRangeFs + { + public static ResultRange DataCorrupted => new ResultRange(ResultFs.ModuleFs, 4000, 4999); + public static ResultRange RomCorrupted => new ResultRange(ResultFs.ModuleFs, 4001, 4299); + public static ResultRange SaveDataCorrupted => new ResultRange(ResultFs.ModuleFs, 4301, 4499); + public static ResultRange NcaCorrupted => new ResultRange(ResultFs.ModuleFs, 4501, 4599); + public static ResultRange IvfcStorageCorrupted => new ResultRange(ResultFs.ModuleFs, 4601, 4639); + public static ResultRange PartitionFsCorrupted => new ResultRange(ResultFs.ModuleFs, 4641, 4659); + public static ResultRange BuiltInStorageCorrupted => new ResultRange(ResultFs.ModuleFs, 4661, 4679); + public static ResultRange FatFsCorrupted => new ResultRange(ResultFs.ModuleFs, 4681, 4699); + public static ResultRange HostFsCorrupted => new ResultRange(ResultFs.ModuleFs, 4701, 4719); + public static ResultRange FileTableCorrupted => new ResultRange(ResultFs.ModuleFs, 4721, 4739); + public static ResultRange Range4811To4819 => new ResultRange(ResultFs.ModuleFs, 4811, 4819); + + public static ResultRange UnexpectedFailure => new ResultRange(ResultFs.ModuleFs, 5000, 5999); + + public static ResultRange EntryNotFound => new ResultRange(ResultFs.ModuleFs, 6600, 6699); + } +} diff --git a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs index 414ea295..a74af539 100644 --- a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs @@ -64,7 +64,7 @@ namespace LibHac.Fs.RomFs if (mode != OpenMode.Read) { - ThrowHelper.ThrowResult(ResultFs.InvalidInput, "RomFs files must be opened read-only."); + ThrowHelper.ThrowResult(ResultFs.InvalidArgument, "RomFs files must be opened read-only."); } return new RomFsFile(BaseStorage, Header.DataOffset + info.Offset, info.Length); diff --git a/src/LibHac/Fs/Save/AllocationTable.cs b/src/LibHac/Fs/Save/AllocationTable.cs index c5e47e38..ad85e744 100644 --- a/src/LibHac/Fs/Save/AllocationTable.cs +++ b/src/LibHac/Fs/Save/AllocationTable.cs @@ -35,6 +35,11 @@ namespace LibHac.Fs.Save if (entries[0].IsSingleBlockSegment()) { length = 1; + + if (entries[0].IsRangeEntry()) + { + ThrowHelper.ThrowResult(ResultFs.AllocationTableIteratedRangeEntryInternal); + } } else { @@ -482,6 +487,11 @@ namespace LibHac.Fs.Save Prev = int.MinValue; } + public bool IsRangeEntry() + { + return Prev != int.MinValue && Prev < 0; + } + public void MakeRangeEntry() { Prev |= unchecked((int)0x80000000); diff --git a/src/LibHac/Fs/Save/SaveResults.cs b/src/LibHac/Fs/Save/SaveResults.cs new file mode 100644 index 00000000..3935db9e --- /dev/null +++ b/src/LibHac/Fs/Save/SaveResults.cs @@ -0,0 +1,127 @@ +namespace LibHac.Fs.Save +{ + internal static class SaveResults + { + public static Result ConvertToExternalResult(Result result) + { + int description = result.Description; + + if (result == Result.Success) + { + return Result.Success; + } + + if (result.Module != ResultFs.ModuleFs) + { + return result; + } + + if (result == ResultFs.Result3002) + { + return ResultFs.Result4302; + } + + if (ResultRangeFs.IvfcStorageCorrupted.Contains(result)) + { + if (result == ResultFs.Result4602) + { + return ResultFs.Result4362; + } + + if (result == ResultFs.Result4603) + { + return ResultFs.Result4363; + } + + if (result == ResultFs.InvalidHashInIvfc) + { + return ResultFs.InvalidHashInSaveIvfc; + } + + if (result == ResultFs.IvfcHashIsEmpty) + { + return ResultFs.SaveIvfcHashIsEmpty; + } + + if (result == ResultFs.InvalidHashInIvfcTopLayer) + { + return ResultFs.InvalidHashInSaveIvfcTopLayer; + } + + return result; + } + + if (ResultRangeFs.BuiltInStorageCorrupted.Contains(result)) + { + if (result == ResultFs.Result4662) + { + return ResultFs.Result4402; + } + + return result; + } + + if (ResultRangeFs.HostFsCorrupted.Contains(result)) + { + if (description > 4701 && description < 4706) + { + return new Result(ResultFs.ModuleFs, description - 260); + } + + return result; + } + + if (ResultRangeFs.Range4811To4819.Contains(result)) + { + if (result == ResultFs.Result4812) + { + return ResultFs.Result4427; + } + + return result; + } + + if (ResultRangeFs.FileTableCorrupted.Contains(result)) + { + if (description > 4721 && description < 4729) + { + return new Result(ResultFs.ModuleFs, (description - 260)); + } + + return result; + } + + if (ResultRangeFs.FatFsCorrupted.Contains(result)) + { + return result; + } + + if (ResultRangeFs.EntryNotFound.Contains(result)) + { + return ResultFs.PathNotFound; + } + + if (result == ResultFs.SaveDataPathAlreadyExists) + { + return ResultFs.PathAlreadyExists; + } + + if (result == ResultFs.PathNotFoundInSaveDataFileTable) + { + return ResultFs.PathNotFound; + } + + if (result == ResultFs.InvalidOffset) + { + return ResultFs.ValueOutOfRange; + } + + if (result == ResultFs.AllocationTableInsufficientFreeBlocks) + { + return ResultFs.InsufficientFreeSpace; + } + + return result; + } + } +} diff --git a/src/LibHac/Kvdb/ImkvdbReader.cs b/src/LibHac/Kvdb/ImkvdbReader.cs index 57da9c72..28556809 100644 --- a/src/LibHac/Kvdb/ImkvdbReader.cs +++ b/src/LibHac/Kvdb/ImkvdbReader.cs @@ -1,9 +1,6 @@ using System; using System.Runtime.CompilerServices; -using static LibHac.Results; -using static LibHac.Kvdb.ResultsKvdb; - namespace LibHac.Kvdb { public ref struct ImkvdbReader @@ -21,19 +18,19 @@ namespace LibHac.Kvdb { entryCount = default; - if (_position + Unsafe.SizeOf() > _data.Length) return ResultKvdbInvalidKeyValue; + if (_position + Unsafe.SizeOf() > _data.Length) return ResultKvdb.InvalidKeyValue; ref ImkvdbHeader header = ref Unsafe.As(ref Unsafe.AsRef(_data[_position])); if (header.Magic != ImkvdbHeader.ExpectedMagic) { - return ResultKvdbInvalidKeyValue; + return ResultKvdb.InvalidKeyValue; } entryCount = header.EntryCount; _position += Unsafe.SizeOf(); - return ResultSuccess; + return Result.Success; } public Result GetEntrySize(out int keySize, out int valueSize) @@ -41,19 +38,19 @@ namespace LibHac.Kvdb keySize = default; valueSize = default; - if (_position + Unsafe.SizeOf() > _data.Length) return ResultKvdbInvalidKeyValue; + if (_position + Unsafe.SizeOf() > _data.Length) return ResultKvdb.InvalidKeyValue; ref ImkvdbEntryHeader header = ref Unsafe.As(ref Unsafe.AsRef(_data[_position])); if (header.Magic != ImkvdbEntryHeader.ExpectedMagic) { - return ResultKvdbInvalidKeyValue; + return ResultKvdb.InvalidKeyValue; } keySize = header.KeySize; valueSize = header.ValueSize; - return ResultSuccess; + return Result.Success; } public Result ReadEntry(out ReadOnlySpan key, out ReadOnlySpan value) @@ -66,14 +63,14 @@ namespace LibHac.Kvdb _position += Unsafe.SizeOf(); - if (_position + keySize + valueSize > _data.Length) return ResultKvdbInvalidKeyValue; + if (_position + keySize + valueSize > _data.Length) return ResultKvdb.InvalidKeyValue; key = _data.Slice(_position, keySize); value = _data.Slice(_position + keySize, valueSize); _position += keySize + valueSize; - return ResultSuccess; + return Result.Success; } } } diff --git a/src/LibHac/Kvdb/KeyValueDatabase.cs b/src/LibHac/Kvdb/KeyValueDatabase.cs index 87b6b15a..f92d00fe 100644 --- a/src/LibHac/Kvdb/KeyValueDatabase.cs +++ b/src/LibHac/Kvdb/KeyValueDatabase.cs @@ -3,9 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using static LibHac.Results; -using static LibHac.Kvdb.ResultsKvdb; - namespace LibHac.Kvdb { // Todo: Save and load from file @@ -21,10 +18,10 @@ namespace LibHac.Kvdb { if (!KvDict.TryGetValue(key, out value)) { - return ResultKvdbKeyNotFound; + return ResultKvdb.KeyNotFound; } - return ResultSuccess; + return Result.Success; } public Result Set(TKey key, TValue value) @@ -33,7 +30,7 @@ namespace LibHac.Kvdb KvDict[key] = value; - return ResultSuccess; + return Result.Success; } public Result ReadDatabaseFromBuffer(ReadOnlySpan data) @@ -59,7 +56,7 @@ namespace LibHac.Kvdb KvDict.Add(key, value); } - return ResultSuccess; + return Result.Success; } public Result WriteDatabaseToBuffer(Span output) @@ -73,7 +70,7 @@ namespace LibHac.Kvdb writer.WriteEntry(entry.Key, entry.Value); } - return ResultSuccess; + return Result.Success; } public int GetExportedSize() diff --git a/src/LibHac/Kvdb/ResultKvdb.cs b/src/LibHac/Kvdb/ResultKvdb.cs new file mode 100644 index 00000000..377e773a --- /dev/null +++ b/src/LibHac/Kvdb/ResultKvdb.cs @@ -0,0 +1,13 @@ +namespace LibHac.Kvdb +{ + public static class ResultKvdb + { + public const int ModuleKvdb = 20; + + public static Result TooLargeKey => new Result(ModuleKvdb, 1); + public static Result KeyNotFound => new Result(ModuleKvdb, 2); + public static Result AllocationFailed => new Result(ModuleKvdb, 4); + public static Result InvalidKeyValue => new Result(ModuleKvdb, 5); + public static Result BufferInsufficient => new Result(ModuleKvdb, 6); + } +} diff --git a/src/LibHac/Kvdb/ResultsKvdb.cs b/src/LibHac/Kvdb/ResultsKvdb.cs deleted file mode 100644 index 333510ec..00000000 --- a/src/LibHac/Kvdb/ResultsKvdb.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace LibHac.Kvdb -{ - public static class ResultsKvdb - { - public const int ModuleKvdb = 20; - - public static Result ResultKvdbTooLargeKey => new Result(ModuleKvdb, 1); - public static Result ResultKvdbKeyNotFound => new Result(ModuleKvdb, 2); - public static Result ResultKvdbAllocationFailed => new Result(ModuleKvdb, 4); - public static Result ResultKvdbInvalidKeyValue => new Result(ModuleKvdb, 5); - public static Result ResultKvdbBufferInsufficient => new Result(ModuleKvdb, 6); - } -} diff --git a/src/LibHac/Result.cs b/src/LibHac/Result.cs index 79121a7e..86fcb228 100644 --- a/src/LibHac/Result.cs +++ b/src/LibHac/Result.cs @@ -3,7 +3,7 @@ namespace LibHac { [Serializable] - public struct Result + public struct Result : IEquatable { public readonly int Value; @@ -31,10 +31,32 @@ namespace LibHac ThrowHelper.ThrowResult(this); } } - } - public static class Results - { - public static Result ResultSuccess => new Result(0); + public override bool Equals(object obj) + { + return obj is Result result && Equals(result); + } + + public bool Equals(Result other) + { + return Value == other.Value; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } + + public static bool operator ==(Result left, Result right) + { + return left.Equals(right); + } + + public static bool operator !=(Result left, Result right) + { + return !left.Equals(right); + } + + public static Result Success => new Result(0); } } diff --git a/src/LibHac/ResultRange.cs b/src/LibHac/ResultRange.cs new file mode 100644 index 00000000..a2edd024 --- /dev/null +++ b/src/LibHac/ResultRange.cs @@ -0,0 +1,21 @@ +namespace LibHac +{ + public struct ResultRange + { + private Result Start { get; } + private Result End { get; } + + public ResultRange(int module, int descriptionStart, int descriptionEnd) + { + Start = new Result(module, descriptionStart); + End = new Result(module, descriptionEnd); + } + + public bool Contains(Result result) + { + return result.Module == Start.Module && + result.Description >= Start.Description && + result.Description <= End.Description; + } + } +}