Add SaveDataCreationInfo2

This commit is contained in:
Alex Barney 2022-04-24 22:33:31 -07:00
parent e13661a4dd
commit 3725c21928
4 changed files with 269 additions and 134 deletions

View file

@ -0,0 +1,33 @@
#pragma warning disable CS0169, CS0649, IDE0051 // Field is never used, Field is never assigned to, Remove unused private members
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace LibHac.Common.FixedArrays;
public struct Array356<T>
{
public const int Length = 356;
private Array256<T> _0;
private Array64<T> _256;
private Array32<T> _320;
private Array4<T> _352;
public ref T this[int i] => ref Items[i];
public Span<T> Items
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length);
}
public readonly ReadOnlySpan<T> ItemsRo
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlySpan<T>(in Array356<T> value) => value.ItemsRo;
}

View file

@ -5,8 +5,127 @@ using LibHac.FsSrv.Impl;
using LibHac.Ncm; using LibHac.Ncm;
using LibHac.Util; using LibHac.Util;
// ReSharper disable once CheckNamespace
namespace LibHac.Fs; namespace LibHac.Fs;
public enum SaveDataSpaceId : byte
{
System = 0,
User = 1,
SdSystem = 2,
Temporary = 3,
SdUser = 4,
ProperSystem = 100,
SafeMode = 101,
BisAuto = 127
}
public enum SaveDataType : byte
{
System = 0,
Account = 1,
Bcat = 2,
Device = 3,
Temporary = 4,
Cache = 5,
SystemBcat = 6
}
public enum SaveDataRank : byte
{
Primary = 0,
Secondary = 1
}
public enum SaveDataFormatType : byte
{
Normal = 0,
NoJournal = 1
}
[Flags]
public enum SaveDataFlags
{
None = 0,
KeepAfterResettingSystemSaveData = 1 << 0,
KeepAfterRefurbishment = 1 << 1,
KeepAfterResettingSystemSaveDataWithoutUserSaveData = 1 << 2,
NeedsSecureDelete = 1 << 3,
Restore = 1 << 4
}
public enum SaveDataState : byte
{
Normal = 0,
Processing = 1,
State2 = 2,
MarkedForDeletion = 3,
Extending = 4,
ImportSuspended = 5
}
public struct SaveDataMetaInfo
{
public int Size;
public SaveDataMetaType Type;
public Array11<byte> Reserved;
}
public enum SaveDataMetaType : byte
{
None = 0,
Thumbnail = 1,
ExtensionContext = 2
}
public struct SaveDataInfo
{
public ulong SaveDataId;
public SaveDataSpaceId SpaceId;
public SaveDataType Type;
public UserId UserId;
public ulong StaticSaveDataId;
public ProgramId ProgramId;
public long Size;
public ushort Index;
public SaveDataRank Rank;
public SaveDataState State;
public Array36<byte> Reserved;
}
public struct SaveDataExtraData
{
public SaveDataAttribute Attribute;
public ulong OwnerId;
public long TimeStamp;
public SaveDataFlags Flags;
public long DataSize;
public long JournalSize;
public long CommitId;
public Array400<byte> Reserved;
}
public struct CommitOption
{
public CommitOptionFlag Flags;
}
[Flags]
public enum CommitOptionFlag
{
None = 0,
ClearRestoreFlag = 1,
SetRestoreFlag = 2
}
public struct HashSalt
{
private Array32<byte> _value;
public Span<byte> Hash => _value.Items;
public readonly ReadOnlySpan<byte> HashRo => _value.ItemsRo;
}
public struct SaveDataAttribute : IEquatable<SaveDataAttribute>, IComparable<SaveDataAttribute> public struct SaveDataAttribute : IEquatable<SaveDataAttribute>, IComparable<SaveDataAttribute>
{ {
public ProgramId ProgramId; public ProgramId ProgramId;
@ -60,8 +179,8 @@ public struct SaveDataAttribute : IEquatable<SaveDataAttribute>, IComparable<Sav
Type == other.Type && Type == other.Type &&
UserId.Equals(other.UserId) && UserId.Equals(other.UserId) &&
StaticSaveDataId == other.StaticSaveDataId && StaticSaveDataId == other.StaticSaveDataId &&
Rank == other.Rank && Index == other.Index &&
Index == other.Index; Rank == other.Rank;
} }
public static bool operator ==(SaveDataAttribute left, SaveDataAttribute right) => left.Equals(right); public static bool operator ==(SaveDataAttribute left, SaveDataAttribute right) => left.Equals(right);
@ -84,9 +203,9 @@ public struct SaveDataAttribute : IEquatable<SaveDataAttribute>, IComparable<Sav
if (userIdComparison != 0) return userIdComparison; if (userIdComparison != 0) return userIdComparison;
int saveDataIdComparison = StaticSaveDataId.CompareTo(other.StaticSaveDataId); int saveDataIdComparison = StaticSaveDataId.CompareTo(other.StaticSaveDataId);
if (saveDataIdComparison != 0) return saveDataIdComparison; if (saveDataIdComparison != 0) return saveDataIdComparison;
int rankComparison = ((int)Rank).CompareTo((int)other.Rank); int indexComparison = Index.CompareTo(other.Index);
if (rankComparison != 0) return rankComparison; if (indexComparison != 0) return indexComparison;
return Index.CompareTo(other.Index); return ((int)Rank).CompareTo((int)other.Rank);
} }
} }
@ -123,6 +242,53 @@ public struct SaveDataCreationInfo
} }
} }
public struct SaveDataCreationInfo2
{
internal const uint SaveDataCreationInfo2Version = 0x00010000;
public uint Version;
public SaveDataAttribute Attribute;
public long Size;
public long JournalSize;
public long BlockSize;
public ulong OwnerId;
public SaveDataFlags Flags;
public SaveDataSpaceId SpaceId;
public SaveDataFormatType FormatType;
public Array2<byte> Reserved1;
public bool IsHashSaltEnabled;
public Array3<byte> Reserved2;
public HashSalt HashSalt;
public SaveDataMetaType MetaType;
public Array3<byte> Reserved3;
public int MetaSize;
public Array356<byte> Reserved4;
public static Result Make(out SaveDataCreationInfo2 creationInfo, in SaveDataAttribute attribute, long size,
long journalSize, long blockSize, ulong ownerId, SaveDataFlags flags, SaveDataSpaceId spaceId,
SaveDataFormatType formatType)
{
UnsafeHelpers.SkipParamInit(out creationInfo);
SaveDataCreationInfo2 tempCreationInfo = default;
tempCreationInfo.Version = SaveDataCreationInfo2Version;
tempCreationInfo.Attribute = attribute;
tempCreationInfo.Size = size;
tempCreationInfo.JournalSize = journalSize;
tempCreationInfo.BlockSize = blockSize;
tempCreationInfo.OwnerId = ownerId;
tempCreationInfo.Flags = flags;
tempCreationInfo.SpaceId = spaceId;
tempCreationInfo.FormatType = formatType;
if (!SaveDataTypesValidity.IsValid(in tempCreationInfo))
return ResultFs.InvalidArgument.Log();
creationInfo = tempCreationInfo;
return Result.Success;
}
}
public struct SaveDataFilter public struct SaveDataFilter
{ {
public bool FilterByProgramId; public bool FilterByProgramId;
@ -201,64 +367,45 @@ public struct SaveDataFilter
} }
} }
public struct HashSalt
{
private Array32<byte> _value;
public Span<byte> Hash => _value.Items;
public readonly ReadOnlySpan<byte> HashRo => _value.ItemsRo;
}
public struct SaveDataMetaInfo
{
public int Size;
public SaveDataMetaType Type;
public Array11<byte> Reserved;
}
public struct SaveDataInfo
{
public ulong SaveDataId;
public SaveDataSpaceId SpaceId;
public SaveDataType Type;
public UserId UserId;
public ulong StaticSaveDataId;
public ProgramId ProgramId;
public long Size;
public ushort Index;
public SaveDataRank Rank;
public SaveDataState State;
public Array36<byte> Reserved;
}
public struct SaveDataExtraData
{
public SaveDataAttribute Attribute;
public ulong OwnerId;
public long TimeStamp;
public SaveDataFlags Flags;
public long DataSize;
public long JournalSize;
public long CommitId;
public Array400<byte> Reserved;
}
public struct CommitOption
{
public CommitOptionFlag Flags;
}
internal static class SaveDataTypesValidity internal static class SaveDataTypesValidity
{ {
public static bool IsValid(in SaveDataAttribute attribute) public static bool IsValid(in SaveDataAttribute attribute)
{ {
return IsValid(in attribute.Type) && IsValid(in attribute.Rank); return IsValid(in attribute.Type)&& IsValid(in attribute.Rank);
} }
public static bool IsValid(in SaveDataCreationInfo creationInfo) public static bool IsValid(in SaveDataCreationInfo creationInfo)
{ {
return creationInfo.Size >= 0 && creationInfo.JournalSize >= 0 && creationInfo.BlockSize >= 0 && return creationInfo.Size >= 0
IsValid(in creationInfo.SpaceId); && creationInfo.JournalSize >= 0
&& creationInfo.BlockSize >= 0
&& IsValid(in creationInfo.SpaceId);
}
public static bool IsValid(in SaveDataCreationInfo2 creationInfo)
{
foreach (byte b in creationInfo.Reserved1.ItemsRo)
if (b != 0) return false;
foreach (byte b in creationInfo.Reserved2.ItemsRo)
if (b != 0) return false;
foreach (byte b in creationInfo.Reserved3.ItemsRo)
if (b != 0) return false;
foreach (byte b in creationInfo.Reserved4.ItemsRo)
if (b != 0) return false;
foreach (byte b in creationInfo.Attribute.Reserved.ItemsRo)
if (b != 0) return false;
return IsValid(in creationInfo.Attribute)
&& creationInfo.Size >= 0
&& creationInfo.JournalSize >= 0
&& creationInfo.BlockSize >= 0
&& IsValid(in creationInfo.SpaceId)
&& IsValid(in creationInfo.FormatType)
&& IsValid(in creationInfo.MetaType);
} }
public static bool IsValid(in SaveDataMetaInfo metaInfo) public static bool IsValid(in SaveDataMetaInfo metaInfo)
@ -277,6 +424,11 @@ internal static class SaveDataTypesValidity
return (uint)type <= (uint)SaveDataType.Cache; return (uint)type <= (uint)SaveDataType.Cache;
} }
public static bool IsValid(in SaveDataFormatType type)
{
return (uint)type <= (uint)SaveDataFormatType.NoJournal;
}
public static bool IsValid(in SaveDataRank rank) public static bool IsValid(in SaveDataRank rank)
{ {
return (uint)rank <= (uint)SaveDataRank.Secondary; return (uint)rank <= (uint)SaveDataRank.Secondary;
@ -284,8 +436,9 @@ internal static class SaveDataTypesValidity
public static bool IsValid(in SaveDataSpaceId spaceId) public static bool IsValid(in SaveDataSpaceId spaceId)
{ {
return (uint)spaceId <= (uint)SaveDataSpaceId.SdUser || spaceId == SaveDataSpaceId.ProperSystem || return (uint)spaceId <= (uint)SaveDataSpaceId.SdUser
spaceId == SaveDataSpaceId.SafeMode; || spaceId == SaveDataSpaceId.ProperSystem
|| spaceId == SaveDataSpaceId.SafeMode;
} }
public static bool IsValid(in SaveDataMetaType metaType) public static bool IsValid(in SaveDataMetaType metaType)

View file

@ -46,18 +46,6 @@ public enum GameCardPartitionRaw
RootWriteOnly = 2 RootWriteOnly = 2
} }
public enum SaveDataSpaceId : byte
{
System = 0,
User = 1,
SdSystem = 2,
Temporary = 3,
SdUser = 4,
ProperSystem = 100,
SafeMode = 101,
BisAuto = 127
}
public enum CustomStorageId public enum CustomStorageId
{ {
System = 0, System = 0,
@ -86,22 +74,6 @@ public enum FileSystemProxyType
RegisteredUpdate = 8 RegisteredUpdate = 8
} }
public enum SaveDataMetaType : byte
{
None = 0,
Thumbnail = 1,
ExtensionContext = 2
}
public enum SaveDataState : byte
{
Normal = 0,
Processing = 1,
State2 = 2,
MarkedForDeletion = 3,
Extending = 4,
ImportSuspended = 5
}
public enum ImageDirectoryId public enum ImageDirectoryId
{ {
@ -153,48 +125,6 @@ public enum OperationId
ReadyLazyLoadFile = 10001 ReadyLazyLoadFile = 10001
} }
public enum SaveDataType : byte
{
System = 0,
Account = 1,
Bcat = 2,
Device = 3,
Temporary = 4,
Cache = 5,
SystemBcat = 6
}
public enum SaveDataRank : byte
{
Primary = 0,
Secondary = 1
}
public enum SaveDataFormatType : byte
{
Normal = 0,
NoJournal = 1
}
[Flags]
public enum SaveDataFlags
{
None = 0,
KeepAfterResettingSystemSaveData = 1 << 0,
KeepAfterRefurbishment = 1 << 1,
KeepAfterResettingSystemSaveDataWithoutUserSaveData = 1 << 2,
NeedsSecureDelete = 1 << 3,
Restore = 1 << 4
}
[Flags]
public enum CommitOptionFlag
{
None = 0,
ClearRestoreFlag = 1,
SetRestoreFlag = 2
}
public enum CacheStorageTargetMedia public enum CacheStorageTargetMedia
{ {
None = 0, None = 0,
@ -294,10 +224,3 @@ public enum SdmmcPort
SdCard = 1, SdCard = 1,
GcAsic = 2 GcAsic = 2
} }
public enum StorageType
{
SaveData = 0,
RomFs = 1,
Authoring = 2
}

View file

@ -41,6 +41,32 @@ public class TypeLayoutTests
Assert.Equal(0x26, GetOffset(in s, in s.Reserved)); Assert.Equal(0x26, GetOffset(in s, in s.Reserved));
} }
[Fact]
public static void SaveDataCreationInfo2_Layout()
{
var s = new SaveDataCreationInfo2();
Assert.Equal(0x200, Unsafe.SizeOf<SaveDataCreationInfo2>());
Assert.Equal(0x00, GetOffset(in s, in s.Version));
Assert.Equal(0x08, GetOffset(in s, in s.Attribute));
Assert.Equal(0x48, GetOffset(in s, in s.Size));
Assert.Equal(0x50, GetOffset(in s, in s.JournalSize));
Assert.Equal(0x58, GetOffset(in s, in s.BlockSize));
Assert.Equal(0x60, GetOffset(in s, in s.OwnerId));
Assert.Equal(0x68, GetOffset(in s, in s.Flags));
Assert.Equal(0x6C, GetOffset(in s, in s.SpaceId));
Assert.Equal(0x6D, GetOffset(in s, in s.FormatType));
Assert.Equal(0x6E, GetOffset(in s, in s.Reserved1));
Assert.Equal(0x70, GetOffset(in s, in s.IsHashSaltEnabled));
Assert.Equal(0x71, GetOffset(in s, in s.Reserved2));
Assert.Equal(0x74, GetOffset(in s, in s.HashSalt));
Assert.Equal(0x94, GetOffset(in s, in s.MetaType));
Assert.Equal(0x95, GetOffset(in s, in s.Reserved3));
Assert.Equal(0x98, GetOffset(in s, in s.MetaSize));
Assert.Equal(0x9C, GetOffset(in s, in s.Reserved4));
}
[Fact] [Fact]
public static void SaveDataFilter_Layout() public static void SaveDataFilter_Layout()
{ {