From c3dfaf14e8a68c967c140d1a8a01a9f7d898693c Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 22 Jul 2019 20:38:59 -0500 Subject: [PATCH 01/46] Add content storage and content meta DB interfaces --- src/LibHac/Cnmt.cs | 71 +++++------------ src/LibHac/Common/Id128.cs | 101 +++++++++++++++++++++++++ src/LibHac/Fs/NcaUtils/Nca.cs | 12 +-- src/LibHac/Fs/RightsId.cs | 47 ++++++++++++ src/LibHac/Fs/UserId.cs | 59 +++++---------- src/LibHac/Ncm/ContentEnums.cs | 40 ++++++++++ src/LibHac/Ncm/ContentId.cs | 47 ++++++++++++ src/LibHac/Ncm/ContentMetaKey.cs | 18 ++--- src/LibHac/Ncm/ContentMetaStructs.cs | 20 +++++ src/LibHac/Ncm/IContentMetaDatabase.cs | 32 ++++++++ src/LibHac/Ncm/IContentStorage.cs | 37 +++++++++ src/LibHac/Ncm/PlaceHolderId.cs | 47 ++++++++++++ src/LibHac/SwitchFs.cs | 23 +++--- 13 files changed, 439 insertions(+), 115 deletions(-) create mode 100644 src/LibHac/Common/Id128.cs create mode 100644 src/LibHac/Fs/RightsId.cs create mode 100644 src/LibHac/Ncm/ContentEnums.cs create mode 100644 src/LibHac/Ncm/ContentId.cs create mode 100644 src/LibHac/Ncm/ContentMetaStructs.cs create mode 100644 src/LibHac/Ncm/IContentMetaDatabase.cs create mode 100644 src/LibHac/Ncm/IContentStorage.cs create mode 100644 src/LibHac/Ncm/PlaceHolderId.cs diff --git a/src/LibHac/Cnmt.cs b/src/LibHac/Cnmt.cs index 9b0d375e..e6869390 100644 --- a/src/LibHac/Cnmt.cs +++ b/src/LibHac/Cnmt.cs @@ -1,6 +1,8 @@ using System.IO; using System.Linq; using LibHac.Fs.NcaUtils; +using LibHac.Ncm; +using ContentType = LibHac.Ncm.ContentType; namespace LibHac { @@ -8,7 +10,7 @@ namespace LibHac { public ulong TitleId { get; } public TitleVersion TitleVersion { get; } - public TitleType Type { get; } + public ContentMetaType Type { get; } public byte FieldD { get; } public int TableOffset { get; } public int ContentEntryCount { get; } @@ -34,8 +36,8 @@ namespace LibHac { TitleId = reader.ReadUInt64(); uint version = reader.ReadUInt32(); - Type = (TitleType)reader.ReadByte(); - TitleVersion = new TitleVersion(version, Type < TitleType.Application); + Type = (ContentMetaType)reader.ReadByte(); + TitleVersion = new TitleVersion(version, Type < ContentMetaType.Application); FieldD = reader.ReadByte(); TableOffset = reader.ReadUInt16(); ContentEntryCount = reader.ReadUInt16(); @@ -44,16 +46,16 @@ namespace LibHac switch (Type) { - case TitleType.Application: + case ContentMetaType.Application: ApplicationTitleId = TitleId; PatchTitleId = reader.ReadUInt64(); MinimumSystemVersion = new TitleVersion(reader.ReadUInt32(), true); break; - case TitleType.Patch: + case ContentMetaType.Patch: ApplicationTitleId = reader.ReadUInt64(); MinimumSystemVersion = new TitleVersion(reader.ReadUInt32(), true); break; - case TitleType.AddOnContent: + case ContentMetaType.AddOnContent: ApplicationTitleId = reader.ReadUInt64(); MinimumApplicationVersion = new TitleVersion(reader.ReadUInt32()); break; @@ -74,7 +76,7 @@ namespace LibHac MetaEntries[i] = new CnmtContentMetaEntry(reader); } - if (Type == TitleType.Patch) + if (Type == ContentMetaType.Patch) { ExtendedData = new CnmtExtended(reader); } @@ -89,7 +91,7 @@ namespace LibHac public byte[] Hash { get; set; } public byte[] NcaId { get; set; } public long Size { get; set; } - public CnmtContentType Type { get; set; } + public ContentType Type { get; set; } public CnmtContentEntry() { } @@ -99,7 +101,7 @@ namespace LibHac NcaId = reader.ReadBytes(0x10); Size = reader.ReadUInt32(); Size |= (long)reader.ReadUInt16() << 32; - Type = (CnmtContentType)reader.ReadByte(); + Type = (ContentType)reader.ReadByte(); reader.BaseStream.Position += 1; } } @@ -108,7 +110,7 @@ namespace LibHac { public ulong TitleId { get; } public TitleVersion Version { get; } - public CnmtContentType Type { get; } + public ContentType Type { get; } public CnmtContentMetaEntry() { } @@ -116,7 +118,7 @@ namespace LibHac { TitleId = reader.ReadUInt64(); Version = new TitleVersion(reader.ReadUInt32(), true); - Type = (CnmtContentType)reader.ReadByte(); + Type = (ContentType)reader.ReadByte(); reader.BaseStream.Position += 3; } } @@ -199,7 +201,7 @@ namespace LibHac { public ulong TitleId { get; } public TitleVersion Version { get; } - public TitleType Type { get; } + public ContentMetaType Type { get; } public byte[] Hash { get; } public short ContentCount { get; } public short CnmtPrevMetaEntryField32 { get; } @@ -209,7 +211,7 @@ namespace LibHac { TitleId = reader.ReadUInt64(); Version = new TitleVersion(reader.ReadUInt32()); - Type = (TitleType)reader.ReadByte(); + Type = (ContentMetaType)reader.ReadByte(); reader.BaseStream.Position += 3; Hash = reader.ReadBytes(0x20); ContentCount = reader.ReadInt16(); @@ -265,8 +267,8 @@ namespace LibHac public long SizeOld { get; } public long SizeNew { get; } public short FragmentCount { get; } - public CnmtContentType Type { get; } - public CnmtDeltaType DeltaType { get; } + public ContentType Type { get; } + public UpdateType DeltaType { get; } public int FragmentSetInfoField30 { get; } @@ -281,8 +283,8 @@ namespace LibHac SizeNew = reader.ReadUInt32(); FragmentCount = reader.ReadInt16(); - Type = (CnmtContentType)reader.ReadByte(); - DeltaType = (CnmtDeltaType)reader.ReadByte(); + Type = (ContentType)reader.ReadByte(); + DeltaType = (UpdateType)reader.ReadByte(); FragmentSetInfoField30 = reader.ReadInt32(); } } @@ -291,14 +293,14 @@ namespace LibHac { public byte[] NcaId { get; } public long Size { get; } - public CnmtContentType Type { get; } + public ContentType Type { get; } public CnmtPrevContent(BinaryReader reader) { NcaId = reader.ReadBytes(0x10); Size = reader.ReadUInt32(); Size |= (long)reader.ReadUInt16() << 32; - Type = (CnmtContentType)reader.ReadByte(); + Type = (ContentType)reader.ReadByte(); reader.BaseStream.Position += 1; } } @@ -314,35 +316,4 @@ namespace LibHac FragmentIndex = reader.ReadInt16(); } } - - public enum CnmtContentType - { - Meta, - Program, - Data, - Control, - HtmlDocument, - LegalInformation, - DeltaFragment - } - - public enum CnmtDeltaType - { - Delta, - Replace, - NewContent - } - - public enum TitleType - { - SystemProgram = 1, - SystemData, - SystemUpdate, - BootImagePackage, - BootImagePackageSafe, - Application = 0x80, - Patch, - AddOnContent, - Delta - } } diff --git a/src/LibHac/Common/Id128.cs b/src/LibHac/Common/Id128.cs new file mode 100644 index 00000000..eab8ab95 --- /dev/null +++ b/src/LibHac/Common/Id128.cs @@ -0,0 +1,101 @@ +using System; +using System.Runtime.InteropServices; + +namespace LibHac.Common +{ + /// + /// A generic 128-bit ID value. + /// + [StructLayout(LayoutKind.Sequential, Size = 0x10)] + public struct Id128 : IEquatable, IComparable, IComparable + { + public readonly ulong High; + public readonly ulong Low; + + public static Id128 InvalidId = new Id128(0, 0); + + public Id128(ulong high, ulong low) + { + High = high; + Low = low; + } + + public Id128(ReadOnlySpan uid) + { + ReadOnlySpan longs = MemoryMarshal.Cast(uid); + + High = longs[0]; + Low = longs[1]; + } + + public bool Equals(Id128 other) + { + return High == other.High && Low == other.Low; + } + + public override bool Equals(object obj) + { + return obj is Fs.UserId other && Equals(other); + } + + public override int GetHashCode() + { + unchecked + { + return (High.GetHashCode() * 397) ^ Low.GetHashCode(); + } + } + + public int CompareTo(Id128 other) + { + // ReSharper disable ImpureMethodCallOnReadonlyValueField + int highComparison = High.CompareTo(other.High); + if (highComparison != 0) return highComparison; + return Low.CompareTo(other.Low); + // ReSharper restore ImpureMethodCallOnReadonlyValueField + } + + public int CompareTo(object obj) + { + if (obj is null) return 1; + return obj is Id128 other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(Id128)}"); + } + + public void ToBytes(Span output) + { + Span longs = MemoryMarshal.Cast(output); + + longs[0] = High; + longs[1] = Low; + } + + public static bool operator ==(Id128 left, Id128 right) + { + return left.Equals(right); + } + + public static bool operator !=(Id128 left, Id128 right) + { + return !left.Equals(right); + } + public static bool operator <(Id128 left, Id128 right) + { + return left.CompareTo(right) < 0; + } + + public static bool operator >(Id128 left, Id128 right) + { + return left.CompareTo(right) > 0; + } + + public static bool operator <=(Id128 left, Id128 right) + { + return left.CompareTo(right) <= 0; + } + + public static bool operator >=(Id128 left, Id128 right) + { + return left.CompareTo(right) >= 0; + } + } +} diff --git a/src/LibHac/Fs/NcaUtils/Nca.cs b/src/LibHac/Fs/NcaUtils/Nca.cs index bad42048..430ef459 100644 --- a/src/LibHac/Fs/NcaUtils/Nca.cs +++ b/src/LibHac/Fs/NcaUtils/Nca.cs @@ -516,7 +516,7 @@ namespace LibHac.Fs.NcaUtils return Header.VerifySignature1(Keyset.NcaHdrFixedKeyModulus); } - internal void GenerateAesCounter(int sectionIndex, CnmtContentType type, int minorVersion) + internal void GenerateAesCounter(int sectionIndex, Ncm.ContentType type, int minorVersion) { int counterType; int counterVersion; @@ -527,14 +527,14 @@ namespace LibHac.Fs.NcaUtils switch (type) { - case CnmtContentType.Program: + case Ncm.ContentType.Program: counterType = sectionIndex + 1; break; - case CnmtContentType.HtmlDocument: - counterType = (int)CnmtContentType.HtmlDocument; + case Ncm.ContentType.HtmlDocument: + counterType = (int)Ncm.ContentType.HtmlDocument; break; - case CnmtContentType.LegalInformation: - counterType = (int)CnmtContentType.LegalInformation; + case Ncm.ContentType.LegalInformation: + counterType = (int)Ncm.ContentType.LegalInformation; break; default: counterType = 0; diff --git a/src/LibHac/Fs/RightsId.cs b/src/LibHac/Fs/RightsId.cs new file mode 100644 index 00000000..11f0969d --- /dev/null +++ b/src/LibHac/Fs/RightsId.cs @@ -0,0 +1,47 @@ +using System; +using System.Runtime.InteropServices; +using LibHac.Common; + +namespace LibHac.Fs +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10)] + public struct RightsId : IEquatable, IComparable, IComparable + { + public readonly Id128 Id; + + public RightsId(ulong high, ulong low) + { + Id = new Id128(high, low); + } + + public RightsId(ReadOnlySpan uid) + { + Id = new Id128(uid); + } + + public bool Equals(RightsId other) => Id == other.Id; + public override bool Equals(object obj) => obj is RightsId other && Equals(other); + + public override int GetHashCode() => Id.GetHashCode(); + + // ReSharper disable once ImpureMethodCallOnReadonlyValueField + public int CompareTo(RightsId other) => Id.CompareTo(other.Id); + + public int CompareTo(object obj) + { + if (obj is null) return 1; + return obj is RightsId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(RightsId)}"); + } + + // ReSharper disable once ImpureMethodCallOnReadonlyValueField + public void ToBytes(Span output) => Id.ToBytes(output); + + public static bool operator ==(RightsId left, RightsId right) => left.Equals(right); + public static bool operator !=(RightsId left, RightsId right) => !left.Equals(right); + + public static bool operator <(RightsId left, RightsId right) => left.CompareTo(right) < 0; + public static bool operator >(RightsId left, RightsId right) => left.CompareTo(right) > 0; + public static bool operator <=(RightsId left, RightsId right) => left.CompareTo(right) <= 0; + public static bool operator >=(RightsId left, RightsId right) => left.CompareTo(right) >= 0; + } +} \ No newline at end of file diff --git a/src/LibHac/Fs/UserId.cs b/src/LibHac/Fs/UserId.cs index 3045249b..4a14fc46 100644 --- a/src/LibHac/Fs/UserId.cs +++ b/src/LibHac/Fs/UserId.cs @@ -1,66 +1,47 @@ using System; using System.Runtime.InteropServices; +using LibHac.Common; namespace LibHac.Fs { + [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct UserId : IEquatable, IComparable, IComparable { - public readonly ulong High; - public readonly ulong Low; + public readonly Id128 Id; public UserId(ulong high, ulong low) { - High = high; - Low = low; + Id = new Id128(high, low); } public UserId(ReadOnlySpan uid) { - ReadOnlySpan longs = MemoryMarshal.Cast(uid); - - High = longs[0]; - Low = longs[1]; + Id = new Id128(uid); } - public bool Equals(UserId other) - { - return High == other.High && Low == other.Low; - } + public bool Equals(UserId other) => Id == other.Id; + public override bool Equals(object obj) => obj is UserId other && Equals(other); - public override bool Equals(object obj) - { - return obj is UserId other && Equals(other); - } + public override int GetHashCode() => Id.GetHashCode(); - public override int GetHashCode() - { - unchecked - { - return (High.GetHashCode() * 397) ^ Low.GetHashCode(); - } - } - - public int CompareTo(UserId other) - { - // ReSharper disable ImpureMethodCallOnReadonlyValueField - int highComparison = High.CompareTo(other.High); - if (highComparison != 0) return highComparison; - return Low.CompareTo(other.Low); - // ReSharper restore ImpureMethodCallOnReadonlyValueField - } + // ReSharper disable once ImpureMethodCallOnReadonlyValueField + public int CompareTo(UserId other) => Id.CompareTo(other.Id); public int CompareTo(object obj) { - if (ReferenceEquals(null, obj)) return 1; + if (obj is null) return 1; return obj is UserId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(UserId)}"); } - public void ToBytes(Span output) - { - Span longs = MemoryMarshal.Cast(output); + // ReSharper disable once ImpureMethodCallOnReadonlyValueField + public void ToBytes(Span output) => Id.ToBytes(output); - longs[0] = High; - longs[1] = Low; - } + public static bool operator ==(UserId left, UserId right) => left.Equals(right); + public static bool operator !=(UserId left, UserId right) => !left.Equals(right); + + public static bool operator <(UserId left, UserId right) => left.CompareTo(right) < 0; + public static bool operator >(UserId left, UserId right) => left.CompareTo(right) > 0; + public static bool operator <=(UserId left, UserId right) => left.CompareTo(right) <= 0; + public static bool operator >=(UserId left, UserId right) => left.CompareTo(right) >= 0; } } diff --git a/src/LibHac/Ncm/ContentEnums.cs b/src/LibHac/Ncm/ContentEnums.cs new file mode 100644 index 00000000..e9197e82 --- /dev/null +++ b/src/LibHac/Ncm/ContentEnums.cs @@ -0,0 +1,40 @@ +namespace LibHac.Ncm +{ + public enum ContentType : byte + { + Meta = 0, + Program = 1, + Data = 2, + Control = 3, + HtmlDocument = 4, + LegalInformation = 5, + DeltaFragment = 6 + } + + public enum ContentMetaType : byte + { + SystemProgram = 1, + SystemData = 2, + SystemUpdate = 3, + BootImagePackage = 4, + BootImagePackageSafe = 5, + Application = 0x80, + Patch = 0x81, + AddOnContent = 0x82, + Delta = 0x83 + } + + public enum ContentMetaAttribute : byte + { + None = 0, + IncludesExFatDriver = 1, + Rebootless = 2 + } + + public enum UpdateType : byte + { + ApplyAsDelta = 0, + Overwrite = 1, + Create = 2 + } +} diff --git a/src/LibHac/Ncm/ContentId.cs b/src/LibHac/Ncm/ContentId.cs new file mode 100644 index 00000000..75c1d120 --- /dev/null +++ b/src/LibHac/Ncm/ContentId.cs @@ -0,0 +1,47 @@ +using System; +using System.Runtime.InteropServices; +using LibHac.Common; + +namespace LibHac.Ncm +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10)] + public struct ContentId : IEquatable, IComparable, IComparable + { + public readonly Id128 Id; + + public ContentId(ulong high, ulong low) + { + Id = new Id128(high, low); + } + + public ContentId(ReadOnlySpan uid) + { + Id = new Id128(uid); + } + + public bool Equals(ContentId other) => Id == other.Id; + public override bool Equals(object obj) => obj is ContentId other && Equals(other); + + public override int GetHashCode() => Id.GetHashCode(); + + // ReSharper disable once ImpureMethodCallOnReadonlyValueField + public int CompareTo(ContentId other) => Id.CompareTo(other.Id); + + public int CompareTo(object obj) + { + if (obj is null) return 1; + return obj is ContentId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(ContentId)}"); + } + + // ReSharper disable once ImpureMethodCallOnReadonlyValueField + public void ToBytes(Span output) => Id.ToBytes(output); + + public static bool operator ==(ContentId left, ContentId right) => left.Equals(right); + public static bool operator !=(ContentId left, ContentId right) => !left.Equals(right); + + public static bool operator <(ContentId left, ContentId right) => left.CompareTo(right) < 0; + public static bool operator >(ContentId left, ContentId right) => left.CompareTo(right) > 0; + public static bool operator <=(ContentId left, ContentId right) => left.CompareTo(right) <= 0; + public static bool operator >=(ContentId left, ContentId right) => left.CompareTo(right) >= 0; + } +} \ No newline at end of file diff --git a/src/LibHac/Ncm/ContentMetaKey.cs b/src/LibHac/Ncm/ContentMetaKey.cs index fda438a4..bdbcbce2 100644 --- a/src/LibHac/Ncm/ContentMetaKey.cs +++ b/src/LibHac/Ncm/ContentMetaKey.cs @@ -8,8 +8,8 @@ namespace LibHac.Ncm { public ulong TitleId { get; private set; } public uint Version { get; private set; } - public byte Type { get; private set; } - public byte Flags { get; private set; } + public ContentMetaType Type { get; private set; } + public ContentMetaAttribute Attributes { get; private set; } public int ExportSize => 0x10; private bool _isFrozen; @@ -20,8 +20,8 @@ namespace LibHac.Ncm BinaryPrimitives.WriteUInt64LittleEndian(output, TitleId); BinaryPrimitives.WriteUInt32LittleEndian(output.Slice(8), Version); - output[0xC] = Type; - output[0xD] = Flags; + output[0xC] = (byte)Type; + output[0xD] = (byte)Attributes; } public void FromBytes(ReadOnlySpan input) @@ -31,8 +31,8 @@ namespace LibHac.Ncm TitleId = BinaryPrimitives.ReadUInt64LittleEndian(input); Version = BinaryPrimitives.ReadUInt32LittleEndian(input.Slice(8)); - Type = input[0xC]; - Flags = input[0xD]; + Type = (ContentMetaType)input[0xC]; + Attributes = (ContentMetaAttribute)input[0xD]; } public void Freeze() => _isFrozen = true; @@ -40,7 +40,7 @@ namespace LibHac.Ncm public bool Equals(ContentMetaKey other) { return other != null && TitleId == other.TitleId && Version == other.Version && - Type == other.Type && Flags == other.Flags; + Type == other.Type && Attributes == other.Attributes; } public override bool Equals(object obj) @@ -56,7 +56,7 @@ namespace LibHac.Ncm int hashCode = TitleId.GetHashCode(); hashCode = (hashCode * 397) ^ (int)Version; hashCode = (hashCode * 397) ^ Type.GetHashCode(); - hashCode = (hashCode * 397) ^ Flags.GetHashCode(); + hashCode = (hashCode * 397) ^ Attributes.GetHashCode(); return hashCode; // ReSharper restore NonReadonlyMemberInGetHashCode } @@ -72,7 +72,7 @@ namespace LibHac.Ncm if (versionComparison != 0) return versionComparison; int typeComparison = Type.CompareTo(other.Type); if (typeComparison != 0) return typeComparison; - return Flags.CompareTo(other.Flags); + return Attributes.CompareTo(other.Attributes); } public int CompareTo(object obj) diff --git a/src/LibHac/Ncm/ContentMetaStructs.cs b/src/LibHac/Ncm/ContentMetaStructs.cs new file mode 100644 index 00000000..992b115d --- /dev/null +++ b/src/LibHac/Ncm/ContentMetaStructs.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; + +namespace LibHac.Ncm +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 1)] + public struct ContentInfo + { + public ContentId contentId; + public uint size1; + public ushort size2; + private ContentType contentType; + private byte IdOffset; + } + + public class ApplicationContentMetaKey + { + public ContentMetaKey Key { get; set; } + public ulong TitleId { get; set; } + } +} diff --git a/src/LibHac/Ncm/IContentMetaDatabase.cs b/src/LibHac/Ncm/IContentMetaDatabase.cs new file mode 100644 index 00000000..90307aee --- /dev/null +++ b/src/LibHac/Ncm/IContentMetaDatabase.cs @@ -0,0 +1,32 @@ +using System; + +namespace LibHac.Ncm +{ + public interface IContentMetaDatabase + { + Result Set(ContentMetaKey key, ReadOnlySpan value); + Result Get(out long valueSize, ContentMetaKey key, Span valueBuffer); + Result Remove(ContentMetaKey key); + Result GetContentIdByType(out ContentId contentId, ContentMetaKey key, ContentType type); + Result ListContentInfo(out int count, Span outInfo, ContentMetaKey key, int startIndex); + + Result List(out int totalEntryCount, out int matchedEntryCount, Span keys, ContentMetaType type, + ulong applicationTitleId, ulong minTitleId, ulong maxTitleId, ContentMetaAttribute attributes); + + Result GetLatestContentMetaKey(out ContentMetaKey key, ulong titleId); + Result ListApplication(out int totalEntryCount, out int matchedEntryCount, Span keys, ContentMetaType type); + Result Has(out bool hasKey, ContentMetaKey key); + Result HasAll(out bool hasAllKeys, ReadOnlySpan key); + Result GetSize(out long size, ContentMetaKey key); + Result GetRequiredSystemVersion(out int version, ContentMetaKey key); + Result GetPatchId(out ulong titleId, ContentMetaKey key); + Result DisableForcibly(); + Result LookupOrphanContent(Span outOrphaned, ReadOnlySpan contentIds); + Result Commit(); + Result HasContent(out bool hasContent, ContentMetaKey key, ContentId contentId); + Result ListContentMetaInfo(out int entryCount, Span outInfo, ContentMetaKey key, int startIndex); + Result GetAttributes(out ContentMetaAttribute attributes, ContentMetaKey key); + Result GetRequiredApplicationVersion(out int version, ContentMetaKey key); + //Result GetContentIdByTypeAndIdOffset(out ContentId contentId, ContentMetaKey key, ContentType type, byte idOffset); + } +} \ No newline at end of file diff --git a/src/LibHac/Ncm/IContentStorage.cs b/src/LibHac/Ncm/IContentStorage.cs new file mode 100644 index 00000000..2cd17ea9 --- /dev/null +++ b/src/LibHac/Ncm/IContentStorage.cs @@ -0,0 +1,37 @@ +using System; +using LibHac.Fs; + +namespace LibHac.Ncm +{ + public interface IContentStorage + { + Result GeneratePlaceHolderId(out PlaceHolderId placeHolderId); + Result CreatePlaceHolder(PlaceHolderId placeHolderId, ContentId contentId, long fileSize); + Result DeletePlaceHolder(PlaceHolderId placeHolderId); + Result HasPlaceHolder(out bool hasPlaceHolder, PlaceHolderId placeHolderId); + Result WritePlaceHolder(PlaceHolderId placeHolderId, long offset, ReadOnlySpan buffer); + Result Register(PlaceHolderId placeHolderId, ContentId contentId); + Result Delete(ContentId contentId); + Result Has(out bool hasContent, ContentId contentId); + Result GetPath(Span outPath, ContentId contentId); + Result GetPlaceHolderPath(Span outPath, PlaceHolderId placeHolderId); + Result CleanupAllPlaceHolder(); + Result ListPlaceHolder(out int count, Span placeHolderIds); + Result GetContentCount(out int count); + Result ListContentId(out int count, Span contentIds, int startOffset); + Result GetSizeFromContentId(out long size, ContentId contentId); + Result DisableForcibly(); + Result RevertToPlaceHolder(PlaceHolderId placeHolderId, ContentId oldContentId, ContentId newContentId); + Result SetPlaceHolderSize(PlaceHolderId placeHolderId, long size); + Result ReadContentIdFile(Span buffer, long size, ContentId contentId, long offset); + Result GetRightsIdFromPlaceHolderId(out RightsId rightsId, out byte keyGeneration, PlaceHolderId placeHolderId); + Result GetRightsIdFromContentId(out RightsId rightsId, out byte keyGeneration, ContentId contentId); + Result WriteContentForDebug(ContentId contentId, long offset, ReadOnlySpan buffer); + Result GetFreeSpaceSize(out long size); + Result GetTotalSpaceSize(out long size); + Result FlushPlaceHolder(); + //Result GetSizeFromPlaceHolderId(out long size, PlaceHolderId placeHolderId); + //Result RepairInvalidFileAttribute(); + //Result GetRightsIdFromPlaceHolderIdWithCache(out RightsId rightsId, out byte keyGeneration, PlaceHolderId placeHolderId, out ContentId cacheContentId); + } +} \ No newline at end of file diff --git a/src/LibHac/Ncm/PlaceHolderId.cs b/src/LibHac/Ncm/PlaceHolderId.cs new file mode 100644 index 00000000..0e31a14d --- /dev/null +++ b/src/LibHac/Ncm/PlaceHolderId.cs @@ -0,0 +1,47 @@ +using System; +using System.Runtime.InteropServices; +using LibHac.Common; + +namespace LibHac.Ncm +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10)] + public struct PlaceHolderId : IEquatable, IComparable, IComparable + { + public readonly Id128 Id; + + public PlaceHolderId(ulong high, ulong low) + { + Id = new Id128(high, low); + } + + public PlaceHolderId(ReadOnlySpan uid) + { + Id = new Id128(uid); + } + + public bool Equals(PlaceHolderId other) => Id == other.Id; + public override bool Equals(object obj) => obj is PlaceHolderId other && Equals(other); + + public override int GetHashCode() => Id.GetHashCode(); + + // ReSharper disable once ImpureMethodCallOnReadonlyValueField + public int CompareTo(PlaceHolderId other) => Id.CompareTo(other.Id); + + public int CompareTo(object obj) + { + if (obj is null) return 1; + return obj is PlaceHolderId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(PlaceHolderId)}"); + } + + // ReSharper disable once ImpureMethodCallOnReadonlyValueField + public void ToBytes(Span output) => Id.ToBytes(output); + + public static bool operator ==(PlaceHolderId left, PlaceHolderId right) => left.Equals(right); + public static bool operator !=(PlaceHolderId left, PlaceHolderId right) => !left.Equals(right); + + public static bool operator <(PlaceHolderId left, PlaceHolderId right) => left.CompareTo(right) < 0; + public static bool operator >(PlaceHolderId left, PlaceHolderId right) => left.CompareTo(right) > 0; + public static bool operator <=(PlaceHolderId left, PlaceHolderId right) => left.CompareTo(right) <= 0; + public static bool operator >=(PlaceHolderId left, PlaceHolderId right) => left.CompareTo(right) >= 0; + } +} \ No newline at end of file diff --git a/src/LibHac/SwitchFs.cs b/src/LibHac/SwitchFs.cs index b3070ec7..3e39ae1d 100644 --- a/src/LibHac/SwitchFs.cs +++ b/src/LibHac/SwitchFs.cs @@ -6,6 +6,7 @@ using System.Linq; using LibHac.Fs; using LibHac.Fs.NcaUtils; using LibHac.Fs.Save; +using LibHac.Ncm; namespace LibHac { @@ -81,7 +82,7 @@ namespace LibHac nca = new SwitchFsNca(new Nca(Keyset, storage)); nca.NcaId = GetNcaFilename(fileEntry.Name, nca); - string extension = nca.Nca.Header.ContentType == ContentType.Meta ? ".cnmt.nca" : ".nca"; + string extension = nca.Nca.Header.ContentType == Fs.NcaUtils.ContentType.Meta ? ".cnmt.nca" : ".nca"; nca.Filename = nca.NcaId + extension; } catch (MissingKeyException ex) @@ -131,7 +132,7 @@ namespace LibHac private void ReadTitles() { - foreach (SwitchFsNca nca in Ncas.Values.Where(x => x.Nca.Header.ContentType == ContentType.Meta)) + foreach (SwitchFsNca nca in Ncas.Values.Where(x => x.Nca.Header.ContentType == Fs.NcaUtils.ContentType.Meta)) { try { @@ -160,11 +161,11 @@ namespace LibHac switch (content.Type) { - case CnmtContentType.Program: - case CnmtContentType.Data: + case Ncm.ContentType.Program: + case Ncm.ContentType.Data: title.MainNca = contentNca; break; - case CnmtContentType.Control: + case Ncm.ContentType.Control: title.ControlNca = contentNca; break; } @@ -201,7 +202,7 @@ namespace LibHac private void CreateApplications() { - foreach (Title title in Titles.Values.Where(x => x.Metadata.Type >= TitleType.Application)) + foreach (Title title in Titles.Values.Where(x => x.Metadata.Type >= ContentMetaType.Application)) { Cnmt meta = title.Metadata; ulong appId = meta.ApplicationTitleId; @@ -229,7 +230,7 @@ namespace LibHac private string GetNcaFilename(string name, SwitchFsNca nca) { - if (nca.Nca.Header.ContentType != ContentType.Meta || !name.EndsWith(".cnmt.nca")) + if (nca.Nca.Header.ContentType != Fs.NcaUtils.ContentType.Meta || !name.EndsWith(".cnmt.nca")) { return Path.GetFileNameWithoutExtension(name); } @@ -343,16 +344,16 @@ namespace LibHac switch (title.Metadata.Type) { - case TitleType.Application: + case ContentMetaType.Application: Main = title; break; - case TitleType.Patch: + case ContentMetaType.Patch: Patch = title; break; - case TitleType.AddOnContent: + case ContentMetaType.AddOnContent: AddOnContent.Add(title); break; - case TitleType.Delta: + case ContentMetaType.Delta: break; } From a052ebb8a171a25f19ba4869428ecbcb1e263f6e Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 19 Aug 2019 21:24:30 -0500 Subject: [PATCH 02/46] Add fscreator interfaces --- src/LibHac/Common/ITimeStampGenerator.cs | 9 +++ src/LibHac/Fs/{DeltaFragment.cs => Delta.cs} | 56 +++++++++---------- src/LibHac/Fs/FsEnums.cs | 45 +++++++++++++++ src/LibHac/Fs/NcaUtils/Nca.cs | 26 ++++----- src/LibHac/Fs/NcaUtils/NcaHeader.cs | 4 +- src/LibHac/Fs/NcaUtils/NcaStructs.cs | 2 +- .../Fs/Save/ISaveDataExtraDataAccessor.cs | 9 +++ ...SaveDataStruct.cs => SaveDataAttribute.cs} | 10 ++-- .../FsService/Creators/FileSystemCreators.cs | 20 +++++++ .../Creators/IBuiltInStorageCreator.cs | 9 +++ .../IBuiltInStorageFileSystemCreator.cs | 11 ++++ .../Creators/IEncryptedFileSystemCreator.cs | 18 ++++++ .../Creators/IFatFileSystemCreator.cs | 9 +++ .../Creators/IGameCardFileSystemCreator.cs | 9 +++ .../Creators/IGameCardStorageCreator.cs | 11 ++++ .../Creators/IMemoryStorageCreator.cs | 11 ++++ .../Creators/IPartitionFileSystemCreator.cs | 9 +++ .../Creators/IRomFileSystemCreator.cs | 9 +++ .../Creators/ISaveDataFileSystemCreator.cs | 18 ++++++ .../Creators/ISdFileSystemCreator.cs | 10 ++++ .../FsService/Creators/ISdStorageCreator.cs | 9 +++ .../Creators/IStorageOnNcaCreator.cs | 13 +++++ .../ISubDirectoryFileSystemCreator.cs | 9 +++ src/LibHac/FsService/GameCardHandle.cs | 7 +++ src/LibHac/SwitchFs.cs | 12 ++-- src/hactoolnet/ProcessDelta.cs | 10 ++-- src/hactoolnet/ProcessNca.cs | 6 +- src/hactoolnet/ProcessXci.cs | 2 +- 28 files changed, 309 insertions(+), 64 deletions(-) create mode 100644 src/LibHac/Common/ITimeStampGenerator.cs rename src/LibHac/Fs/{DeltaFragment.cs => Delta.cs} (67%) create mode 100644 src/LibHac/Fs/FsEnums.cs create mode 100644 src/LibHac/Fs/Save/ISaveDataExtraDataAccessor.cs rename src/LibHac/Fs/{SaveDataStruct.cs => SaveDataAttribute.cs} (88%) create mode 100644 src/LibHac/FsService/Creators/FileSystemCreators.cs create mode 100644 src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs create mode 100644 src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/IFatFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/IGameCardStorageCreator.cs create mode 100644 src/LibHac/FsService/Creators/IMemoryStorageCreator.cs create mode 100644 src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/IRomFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/ISdFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/ISdStorageCreator.cs create mode 100644 src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs create mode 100644 src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs create mode 100644 src/LibHac/FsService/GameCardHandle.cs diff --git a/src/LibHac/Common/ITimeStampGenerator.cs b/src/LibHac/Common/ITimeStampGenerator.cs new file mode 100644 index 00000000..3d0c528b --- /dev/null +++ b/src/LibHac/Common/ITimeStampGenerator.cs @@ -0,0 +1,9 @@ +using System; + +namespace LibHac.Common +{ + public interface ITimeStampGenerator + { + DateTimeOffset Generate(); + } +} \ No newline at end of file diff --git a/src/LibHac/Fs/DeltaFragment.cs b/src/LibHac/Fs/Delta.cs similarity index 67% rename from src/LibHac/Fs/DeltaFragment.cs rename to src/LibHac/Fs/Delta.cs index 77711ebd..26fc43d9 100644 --- a/src/LibHac/Fs/DeltaFragment.cs +++ b/src/LibHac/Fs/Delta.cs @@ -4,31 +4,31 @@ using System.IO; namespace LibHac.Fs { - public class DeltaFragment + public class Delta { private const string Ndv0Magic = "NDV0"; - private IStorage Original { get; set; } - private IStorage Delta { get; } - public DeltaFragmentHeader Header { get; } - private List Segments { get; } = new List(); + private IStorage OriginalStorage { get; set; } + private IStorage DeltaStorage { get; } + public DeltaHeader Header { get; } + private List Segments { get; } = new List(); - public DeltaFragment(IStorage delta, IStorage originalData) : this(delta) + public Delta(IStorage deltaStorage, IStorage originalData) : this(deltaStorage) { SetBaseStorage(originalData); } - public DeltaFragment(IStorage delta) + public Delta(IStorage deltaStorage) { - Delta = delta; + DeltaStorage = deltaStorage; - if (Delta.GetSize() < 0x40) throw new InvalidDataException("Delta file is too small."); + if (DeltaStorage.GetSize() < 0x40) throw new InvalidDataException("Delta file is too small."); - Header = new DeltaFragmentHeader(delta.AsFile(OpenMode.Read)); + Header = new DeltaHeader(deltaStorage.AsFile(OpenMode.Read)); if (Header.Magic != Ndv0Magic) throw new InvalidDataException("NDV0 magic value is missing."); - long fragmentSize = Header.FragmentHeaderSize + Header.FragmentBodySize; - if (Delta.GetSize() < fragmentSize) + long fragmentSize = Header.HeaderSize + Header.BodySize; + if (DeltaStorage.GetSize() < fragmentSize) { throw new InvalidDataException($"Delta file is smaller than the header indicates. (0x{fragmentSize} bytes)"); } @@ -38,9 +38,9 @@ namespace LibHac.Fs public void SetBaseStorage(IStorage baseStorage) { - Original = baseStorage; + OriginalStorage = baseStorage; - if (Original.GetSize() != Header.OriginalSize) + if (OriginalStorage.GetSize() != Header.OriginalSize) { throw new InvalidDataException($"Original file size does not match the size in the delta header. (0x{Header.OriginalSize} bytes)"); } @@ -48,13 +48,13 @@ namespace LibHac.Fs public IStorage GetPatchedStorage() { - if (Original == null) throw new InvalidOperationException("Cannot apply a delta patch without a base file."); + if (OriginalStorage == null) throw new InvalidOperationException("Cannot apply a delta patch without a base file."); var storages = new List(); - foreach (DeltaFragmentSegment segment in Segments) + foreach (DeltaSegment segment in Segments) { - IStorage source = segment.IsInOriginal ? Original : Delta; + IStorage source = segment.IsInOriginal ? OriginalStorage : DeltaStorage; // todo Do this without tons of SubStorages IStorage sub = source.Slice(segment.SourceOffset, segment.Size); @@ -67,9 +67,9 @@ namespace LibHac.Fs private void ParseDeltaStructure() { - var reader = new FileReader(Delta.AsFile(OpenMode.Read)); + var reader = new FileReader(DeltaStorage.AsFile(OpenMode.Read)); - reader.Position = Header.FragmentHeaderSize; + reader.Position = Header.HeaderSize; long offset = 0; @@ -79,7 +79,7 @@ namespace LibHac.Fs if (seek > 0) { - var segment = new DeltaFragmentSegment() + var segment = new DeltaSegment() { SourceOffset = offset, Size = seek, @@ -92,7 +92,7 @@ namespace LibHac.Fs if (size > 0) { - var segment = new DeltaFragmentSegment() + var segment = new DeltaSegment() { SourceOffset = reader.Position, Size = size, @@ -131,30 +131,30 @@ namespace LibHac.Fs } } - internal class DeltaFragmentSegment + internal class DeltaSegment { public long SourceOffset { get; set; } public int Size { get; set; } public bool IsInOriginal { get; set; } } - public class DeltaFragmentHeader + public class DeltaHeader { public string Magic { get; } public long OriginalSize { get; } public long NewSize { get; } - public long FragmentHeaderSize { get; } - public long FragmentBodySize { get; } + public long HeaderSize { get; } + public long BodySize { get; } - public DeltaFragmentHeader(IFile header) + public DeltaHeader(IFile header) { var reader = new FileReader(header); Magic = reader.ReadAscii(4); OriginalSize = reader.ReadInt64(8); NewSize = reader.ReadInt64(); - FragmentHeaderSize = reader.ReadInt64(); - FragmentBodySize = reader.ReadInt64(); + HeaderSize = reader.ReadInt64(); + BodySize = reader.ReadInt64(); } } } diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs new file mode 100644 index 00000000..d5f09439 --- /dev/null +++ b/src/LibHac/Fs/FsEnums.cs @@ -0,0 +1,45 @@ +namespace LibHac.Fs +{ + public enum BisPartitionId + { + BootPartition1Root = 0, + BootPartition2Root = 10, + UserDataRoot = 20, + BootConfigAndPackage2Part1 = 21, + BootConfigAndPackage2Part2 = 22, + BootConfigAndPackage2Part3 = 23, + BootConfigAndPackage2Part4 = 24, + BootConfigAndPackage2Part5 = 25, + BootConfigAndPackage2Part6 = 26, + CalibrationBinary = 27, + CalibrationFile = 28, + SafeMode = 29, + User = 30, + System = 31, + SystemProperEncryption = 32, + SystemProperPartition = 33, + Invalid = 35 + } + + public enum ContentStorageId + { + System = 0, + User = 1, + SdCard = 2 + } + + public enum GameCardPartition + { + Update = 0, + Normal = 1, + Secure = 2, + Logo = 3 + } + + public enum GameCardPartitionRaw + { + Normal = 0, + Secure = 1, + Writable = 2 + } +} diff --git a/src/LibHac/Fs/NcaUtils/Nca.cs b/src/LibHac/Fs/NcaUtils/Nca.cs index 430ef459..7296aa5c 100644 --- a/src/LibHac/Fs/NcaUtils/Nca.cs +++ b/src/LibHac/Fs/NcaUtils/Nca.cs @@ -336,7 +336,7 @@ namespace LibHac.Fs.NcaUtils return GetSectionIndexFromType(type, Header.ContentType); } - public static int GetSectionIndexFromType(NcaSectionType type, ContentType contentType) + public static int GetSectionIndexFromType(NcaSectionType type, NcaContentType contentType) { if (!TryGetSectionIndexFromType(type, contentType, out int index)) { @@ -346,17 +346,17 @@ namespace LibHac.Fs.NcaUtils return index; } - public static bool TryGetSectionIndexFromType(NcaSectionType type, ContentType contentType, out int index) + public static bool TryGetSectionIndexFromType(NcaSectionType type, NcaContentType contentType, out int index) { switch (type) { - case NcaSectionType.Code when contentType == ContentType.Program: + case NcaSectionType.Code when contentType == NcaContentType.Program: index = 0; return true; - case NcaSectionType.Data when contentType == ContentType.Program: + case NcaSectionType.Data when contentType == NcaContentType.Program: index = 1; return true; - case NcaSectionType.Logo when contentType == ContentType.Program: + case NcaSectionType.Logo when contentType == NcaContentType.Program: index = 2; return true; case NcaSectionType.Data: @@ -368,7 +368,7 @@ namespace LibHac.Fs.NcaUtils } } - public static NcaSectionType GetSectionTypeFromIndex(int index, ContentType contentType) + public static NcaSectionType GetSectionTypeFromIndex(int index, NcaContentType contentType) { if (!TryGetSectionTypeFromIndex(index, contentType, out NcaSectionType type)) { @@ -378,17 +378,17 @@ namespace LibHac.Fs.NcaUtils return type; } - public static bool TryGetSectionTypeFromIndex(int index, ContentType contentType, out NcaSectionType type) + public static bool TryGetSectionTypeFromIndex(int index, NcaContentType contentType, out NcaSectionType type) { switch (index) { - case 0 when contentType == ContentType.Program: + case 0 when contentType == NcaContentType.Program: type = NcaSectionType.Code; return true; - case 1 when contentType == ContentType.Program: + case 1 when contentType == NcaContentType.Program: type = NcaSectionType.Data; return true; - case 2 when contentType == ContentType.Program: + case 2 when contentType == NcaContentType.Program: type = NcaSectionType.Logo; return true; case 0: @@ -545,11 +545,11 @@ namespace LibHac.Fs.NcaUtils // Haven't checked delta fragment NCAs switch (Header.ContentType) { - case ContentType.Program: - case ContentType.Manual: + case NcaContentType.Program: + case NcaContentType.Manual: counterVersion = Math.Max(minorVersion - 1, 0); break; - case ContentType.PublicData: + case NcaContentType.PublicData: counterVersion = minorVersion << 16; break; default: diff --git a/src/LibHac/Fs/NcaUtils/NcaHeader.cs b/src/LibHac/Fs/NcaUtils/NcaHeader.cs index 03a32ca3..d15dcbf9 100644 --- a/src/LibHac/Fs/NcaUtils/NcaHeader.cs +++ b/src/LibHac/Fs/NcaUtils/NcaHeader.cs @@ -44,9 +44,9 @@ namespace LibHac.Fs.NcaUtils set => Header.DistributionType = (byte)value; } - public ContentType ContentType + public NcaContentType ContentType { - get => (ContentType)Header.ContentType; + get => (NcaContentType)Header.ContentType; set => Header.ContentType = (byte)value; } diff --git a/src/LibHac/Fs/NcaUtils/NcaStructs.cs b/src/LibHac/Fs/NcaUtils/NcaStructs.cs index cb583f34..f8fdc052 100644 --- a/src/LibHac/Fs/NcaUtils/NcaStructs.cs +++ b/src/LibHac/Fs/NcaUtils/NcaStructs.cs @@ -41,7 +41,7 @@ Logo }; - public enum ContentType + public enum NcaContentType { Program, Meta, diff --git a/src/LibHac/Fs/Save/ISaveDataExtraDataAccessor.cs b/src/LibHac/Fs/Save/ISaveDataExtraDataAccessor.cs new file mode 100644 index 00000000..6b93ffab --- /dev/null +++ b/src/LibHac/Fs/Save/ISaveDataExtraDataAccessor.cs @@ -0,0 +1,9 @@ +namespace LibHac.Fs.Save +{ + public interface ISaveDataExtraDataAccessor + { + Result Write(ExtraData data); + Result Commit(); + Result Read(out ExtraData data); + } +} diff --git a/src/LibHac/Fs/SaveDataStruct.cs b/src/LibHac/Fs/SaveDataAttribute.cs similarity index 88% rename from src/LibHac/Fs/SaveDataStruct.cs rename to src/LibHac/Fs/SaveDataAttribute.cs index a0a71f49..d37c7ed3 100644 --- a/src/LibHac/Fs/SaveDataStruct.cs +++ b/src/LibHac/Fs/SaveDataAttribute.cs @@ -5,7 +5,7 @@ using LibHac.Kvdb; namespace LibHac.Fs { - public class SaveDataStruct : IComparable, IComparable, IEquatable, IExportable + public class SaveDataAttribute : 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(SaveDataStruct other) + public bool Equals(SaveDataAttribute 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 SaveDataStruct other && Equals(other); + return obj is SaveDataAttribute other && Equals(other); } public override int GetHashCode() @@ -71,7 +71,7 @@ namespace LibHac.Fs } } - public int CompareTo(SaveDataStruct other) + public int CompareTo(SaveDataAttribute 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 SaveDataStruct other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(SaveDataStruct)}"); + return obj is SaveDataAttribute other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(SaveDataAttribute)}"); } } } diff --git a/src/LibHac/FsService/Creators/FileSystemCreators.cs b/src/LibHac/FsService/Creators/FileSystemCreators.cs new file mode 100644 index 00000000..f38d476c --- /dev/null +++ b/src/LibHac/FsService/Creators/FileSystemCreators.cs @@ -0,0 +1,20 @@ +namespace LibHac.FsService.Creators +{ + public class FileSystemCreators + { + public IRomFileSystemCreator RomFileSystemCreator { get; set; } + public IPartitionFileSystemCreator PartitionFileSystemCreator { get; set; } + public IStorageOnNcaCreator StorageOnNcaCreator { get; set; } + public IFatFileSystemCreator FatFileSystemCreator { get; set; } + public ISubDirectoryFileSystemCreator SubDirectoryFileSystemCreator { get; set; } + public IBuiltInStorageCreator BuiltInStorageCreator { get; set; } + public ISdStorageCreator SdStorageCreator { get; set; } + public ISaveDataFileSystemCreator SaveDataFileSystemCreator { get; set; } + public IGameCardStorageCreator GameCardStorageCreator { get; set; } + public IGameCardFileSystemCreator GameCardFileSystemCreator { get; set; } + public IEncryptedFileSystemCreator EncryptedFileSystemCreator { get; set; } + public IMemoryStorageCreator MemoryStorageCreator { get; set; } + public IBuiltInStorageFileSystemCreator BuiltInStorageFileSystemCreator { get; set; } + public ISdFileSystemCreator SdFileSystemCreator { get; set; } + } +} diff --git a/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs b/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs new file mode 100644 index 00000000..e7e6df62 --- /dev/null +++ b/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs @@ -0,0 +1,9 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IBuiltInStorageCreator + { + Result Create(out IStorage storage, BisPartitionId partitionId); + } +} diff --git a/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs b/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs new file mode 100644 index 00000000..b94ca90a --- /dev/null +++ b/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs @@ -0,0 +1,11 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IBuiltInStorageFileSystemCreator + { + Result Create(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId); + Result CreateFatFileSystem(out IFileSystem fileSystem, BisPartitionId partitionId); + Result SetBisRootForHost(BisPartitionId partitionId, string rootPath); + } +} \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs b/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs new file mode 100644 index 00000000..f6cfde96 --- /dev/null +++ b/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs @@ -0,0 +1,18 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IEncryptedFileSystemCreator + { + Result Create(out IFileSystem encryptedFileSystem, IFileSystem baseFileSystem, EncryptedFsKeyId keyId, + ReadOnlySpan encryptionSeed); + } + + public enum EncryptedFsKeyId + { + Save = 0, + Content = 1, + CustomStorage = 2 + } +} diff --git a/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs b/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs new file mode 100644 index 00000000..b86fac56 --- /dev/null +++ b/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs @@ -0,0 +1,9 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IFatFileSystemCreator + { + Result Create(out IFileSystem fileSystem, IStorage baseStorage); + } +} \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs b/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs new file mode 100644 index 00000000..550ce9c6 --- /dev/null +++ b/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs @@ -0,0 +1,9 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IGameCardFileSystemCreator + { + Result Create(out IFileSystem fileSystem, GameCardHandle handle, GameCardPartition partitionType); + } +} \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs b/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs new file mode 100644 index 00000000..e5fdfc19 --- /dev/null +++ b/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs @@ -0,0 +1,11 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IGameCardStorageCreator + { + Result CreateNormal(GameCardHandle handle, out IStorage storage); + Result CreateSecure(GameCardHandle handle, out IStorage storage); + Result CreateWritable(GameCardHandle handle, out IStorage storage); + } +} \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs b/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs new file mode 100644 index 00000000..403dbe01 --- /dev/null +++ b/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs @@ -0,0 +1,11 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IMemoryStorageCreator + { + Result Create(out IStorage storage, out Memory buffer, int storageId); + Result RegisterBuffer(int storageId, Memory buffer); + } +} diff --git a/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs b/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs new file mode 100644 index 00000000..af99e8cd --- /dev/null +++ b/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs @@ -0,0 +1,9 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IPartitionFileSystemCreator + { + Result Create(out IFileSystem fileSystem, IStorage pFsStorage); + } +} diff --git a/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs b/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs new file mode 100644 index 00000000..b2ea3957 --- /dev/null +++ b/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs @@ -0,0 +1,9 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IRomFileSystemCreator + { + Result Create(out IFileSystem fileSystem, IStorage romFsStorage); + } +} diff --git a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs new file mode 100644 index 00000000..4cd3b224 --- /dev/null +++ b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs @@ -0,0 +1,18 @@ +using System; +using LibHac.Common; +using LibHac.Fs; +using LibHac.Fs.Save; + +namespace LibHac.FsService.Creators +{ + public interface ISaveDataFileSystemCreator + { + Result CreateFile(out IFile file, IFileSystem sourceFileSystem, ulong saveDataId, OpenMode openMode); + + Result Create(out IFileSystem fileSystem, out ISaveDataExtraDataAccessor extraDataAccessor, + IFileSystem sourceFileSystem, ulong saveDataId, bool allowDirectorySaveData, bool useDeviceUniqueMac, + SaveDataType type, ITimeStampGenerator timeStampGenerator); + + Result SetSdCardEncryptionSeed(ReadOnlySpan seed); + } +} diff --git a/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs new file mode 100644 index 00000000..041f0217 --- /dev/null +++ b/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs @@ -0,0 +1,10 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface ISdFileSystemCreator + { + Result Create(out IFileSystem fileSystem); + Result Format(bool closeOpenEntries); + } +} diff --git a/src/LibHac/FsService/Creators/ISdStorageCreator.cs b/src/LibHac/FsService/Creators/ISdStorageCreator.cs new file mode 100644 index 00000000..691359bb --- /dev/null +++ b/src/LibHac/FsService/Creators/ISdStorageCreator.cs @@ -0,0 +1,9 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface ISdStorageCreator + { + Result Create(out IStorage storage); + } +} diff --git a/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs b/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs new file mode 100644 index 00000000..4c76e12a --- /dev/null +++ b/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs @@ -0,0 +1,13 @@ +using LibHac.Fs; +using LibHac.Fs.NcaUtils; + +namespace LibHac.FsService.Creators +{ + public interface IStorageOnNcaCreator + { + Result Create(out IStorage storage, out NcaFsHeader fsHeader, Nca nca, int fsIndex, bool isCodeFs); + Result CreateWithPatch(out IStorage storage, out NcaFsHeader fsHeader, Nca baseNca, Nca patchNca, int fsIndex, bool isCodeFs); + Result OpenNca(out Nca nca, IStorage ncaStorage); + Result VerifyAcidSignature(IFileSystem codeFileSystem, Nca nca); + } +} diff --git a/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs new file mode 100644 index 00000000..3bae3cb7 --- /dev/null +++ b/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs @@ -0,0 +1,9 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface ISubDirectoryFileSystemCreator + { + Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, string path); + } +} \ No newline at end of file diff --git a/src/LibHac/FsService/GameCardHandle.cs b/src/LibHac/FsService/GameCardHandle.cs new file mode 100644 index 00000000..1753a869 --- /dev/null +++ b/src/LibHac/FsService/GameCardHandle.cs @@ -0,0 +1,7 @@ +namespace LibHac.FsService +{ + public struct GameCardHandle + { + public int Value; + } +} diff --git a/src/LibHac/SwitchFs.cs b/src/LibHac/SwitchFs.cs index 3e39ae1d..98b42155 100644 --- a/src/LibHac/SwitchFs.cs +++ b/src/LibHac/SwitchFs.cs @@ -82,7 +82,7 @@ namespace LibHac nca = new SwitchFsNca(new Nca(Keyset, storage)); nca.NcaId = GetNcaFilename(fileEntry.Name, nca); - string extension = nca.Nca.Header.ContentType == Fs.NcaUtils.ContentType.Meta ? ".cnmt.nca" : ".nca"; + string extension = nca.Nca.Header.ContentType == NcaContentType.Meta ? ".cnmt.nca" : ".nca"; nca.Filename = nca.NcaId + extension; } catch (MissingKeyException ex) @@ -132,7 +132,7 @@ namespace LibHac private void ReadTitles() { - foreach (SwitchFsNca nca in Ncas.Values.Where(x => x.Nca.Header.ContentType == Fs.NcaUtils.ContentType.Meta)) + foreach (SwitchFsNca nca in Ncas.Values.Where(x => x.Nca.Header.ContentType == NcaContentType.Meta)) { try { @@ -161,11 +161,11 @@ namespace LibHac switch (content.Type) { - case Ncm.ContentType.Program: - case Ncm.ContentType.Data: + case ContentType.Program: + case ContentType.Data: title.MainNca = contentNca; break; - case Ncm.ContentType.Control: + case ContentType.Control: title.ControlNca = contentNca; break; } @@ -230,7 +230,7 @@ namespace LibHac private string GetNcaFilename(string name, SwitchFsNca nca) { - if (nca.Nca.Header.ContentType != Fs.NcaUtils.ContentType.Meta || !name.EndsWith(".cnmt.nca")) + if (nca.Nca.Header.ContentType != NcaContentType.Meta || !name.EndsWith(".cnmt.nca")) { return Path.GetFileNameWithoutExtension(name); } diff --git a/src/hactoolnet/ProcessDelta.cs b/src/hactoolnet/ProcessDelta.cs index 0c966a34..e59666c4 100644 --- a/src/hactoolnet/ProcessDelta.cs +++ b/src/hactoolnet/ProcessDelta.cs @@ -38,7 +38,7 @@ namespace hactoolnet catch (InvalidDataException) { } // Ignore non-NCA3 files } - var delta = new DeltaFragment(deltaStorage); + var delta = new Delta(deltaStorage); if (ctx.Options.BaseFile != null) { @@ -61,18 +61,18 @@ namespace hactoolnet } } - private static string Print(this DeltaFragment delta) + private static string Print(this Delta delta) { int colLen = 36; var sb = new StringBuilder(); sb.AppendLine(); - sb.AppendLine("Delta Fragment:"); + sb.AppendLine("Delta File:"); PrintItem(sb, colLen, "Magic:", delta.Header.Magic); PrintItem(sb, colLen, "Base file size:", $"0x{delta.Header.OriginalSize:x12}"); PrintItem(sb, colLen, "New file size:", $"0x{delta.Header.NewSize:x12}"); - PrintItem(sb, colLen, "Fragment header size:", $"0x{delta.Header.FragmentHeaderSize:x12}"); - PrintItem(sb, colLen, "Fragment body size:", $"0x{delta.Header.FragmentBodySize:x12}"); + PrintItem(sb, colLen, "Delta header size:", $"0x{delta.Header.HeaderSize:x12}"); + PrintItem(sb, colLen, "Delta body size:", $"0x{delta.Header.BodySize:x12}"); return sb.ToString(); } diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index 590619fc..7f644940 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -128,7 +128,7 @@ namespace hactoolnet if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null) { - if (nca.Header.ContentType != ContentType.Program) + if (nca.Header.ContentType != NcaContentType.Program) { ctx.Logger.LogMessage("NCA's content type is not \"Program\""); return; @@ -201,7 +201,7 @@ namespace hactoolnet private static Validity VerifySignature2(this Nca nca) { - if (nca.Header.ContentType != ContentType.Program) return Validity.Unchecked; + if (nca.Header.ContentType != NcaContentType.Program) return Validity.Unchecked; IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid); if (!pfs.FileExists("main.npdm")) return Validity.Unchecked; @@ -266,7 +266,7 @@ namespace hactoolnet if (!nca.Header.IsSectionEnabled(i)) continue; NcaFsHeader sectHeader = nca.Header.GetFsHeader(i); - bool isExefs = nca.Header.ContentType == ContentType.Program && i == 0; + bool isExefs = nca.Header.ContentType == NcaContentType.Program && i == 0; sb.AppendLine($" Section {i}:"); PrintItem(sb, colLen, " Offset:", $"0x{nca.Header.GetSectionStartOffset(i):x12}"); diff --git a/src/hactoolnet/ProcessXci.cs b/src/hactoolnet/ProcessXci.cs index cbddcfdb..74d9996f 100644 --- a/src/hactoolnet/ProcessXci.cs +++ b/src/hactoolnet/ProcessXci.cs @@ -127,7 +127,7 @@ namespace hactoolnet IStorage ncaStorage = partition.OpenFile(fileEntry, OpenMode.Read).AsStorage(); var nca = new Nca(ctx.Keyset, ncaStorage); - if (nca.Header.ContentType == ContentType.Program) + if (nca.Header.ContentType == NcaContentType.Program) { mainNca = nca; } From 82c5c5d9a0d1443f5a29c6f0d298ab2a47bdc3c4 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Thu, 22 Aug 2019 14:56:03 -0500 Subject: [PATCH 03/46] Create FileSystemProxy class --- src/LibHac/Fs/PathTools.cs | 1 + .../Creators/ISaveDataFileSystemCreator.cs | 2 +- src/LibHac/FsService/FileSystemProxy.cs | 93 +++++++++++++++++++ src/LibHac/FsService/FileSystemProxyCore.cs | 85 +++++++++++++++++ src/LibHac/FsService/FileSystemService.cs | 6 ++ 5 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 src/LibHac/FsService/FileSystemProxy.cs create mode 100644 src/LibHac/FsService/FileSystemProxyCore.cs create mode 100644 src/LibHac/FsService/FileSystemService.cs diff --git a/src/LibHac/Fs/PathTools.cs b/src/LibHac/Fs/PathTools.cs index 97dc2a76..538bd218 100644 --- a/src/LibHac/Fs/PathTools.cs +++ b/src/LibHac/Fs/PathTools.cs @@ -13,6 +13,7 @@ namespace LibHac.Fs public static readonly char DirectorySeparator = '/'; public static readonly char MountSeparator = ':'; internal const int MountNameLength = 0xF; + internal const int MaxPathLength = 0x300; public static string Normalize(string inPath) { diff --git a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs index 4cd3b224..335d65e2 100644 --- a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs @@ -13,6 +13,6 @@ namespace LibHac.FsService.Creators IFileSystem sourceFileSystem, ulong saveDataId, bool allowDirectorySaveData, bool useDeviceUniqueMac, SaveDataType type, ITimeStampGenerator timeStampGenerator); - Result SetSdCardEncryptionSeed(ReadOnlySpan seed); + void SetSdCardEncryptionSeed(ReadOnlySpan seed); } } diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs new file mode 100644 index 00000000..0b7baf0e --- /dev/null +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -0,0 +1,93 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService +{ + public class FileSystemProxy + { + private FileSystemProxyCore FsProxyCore { get; } + public long CurrentProcess { get; private set; } + + public long SaveDataSize { get; private set; } + public long SaveDataJournalSize { get; private set; } + public string SaveDataRootPath { get; private set; } + public bool AutoCreateSaveData { get; private set; } + + public Result SetCurrentProcess(long processId) + { + CurrentProcess = processId; + + return Result.Success; + } + + public Result DisableAutoSaveDataCreation() + { + AutoCreateSaveData = false; + + return Result.Success; + } + + public Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize) + { + if (saveDataSize < 0 || saveDataJournalSize < 0) + { + return ResultFs.InvalidSize; + } + + SaveDataSize = saveDataSize; + SaveDataJournalSize = saveDataJournalSize; + + return Result.Success; + } + + public Result SetSaveDataRootPath(string path) + { + // Missing permission check + + if (path.Length > PathTools.MaxPathLength) + { + return ResultFs.TooLongPath; + } + + SaveDataRootPath = path; + + return Result.Success; + } + + public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + return FsProxyCore.OpenBisFileSystem(out fileSystem, rootPath, partitionId); + } + + public Result OpenSdCardFileSystem(out IFileSystem fileSystem) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + return FsProxyCore.OpenSdCardFileSystem(out fileSystem); + } + + public Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + return FsProxyCore.OpenContentStorageFileSystem(out fileSystem, storageId); + } + + public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) + { + // todo: use struct instead of byte span + if (seed.Length != 0x16) return ResultFs.InvalidSize; + + // Missing permission check + + Result res = FsProxyCore.SetSdCardEncryptionSeed(seed); + if (res.IsFailure()) return res; + + // todo: Reset save data indexer + + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs new file mode 100644 index 00000000..25c486c0 --- /dev/null +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -0,0 +1,85 @@ +using System; +using LibHac.Fs; +using LibHac.FsService.Creators; + +namespace LibHac.FsService +{ + public class FileSystemProxyCore + { + private FileSystemCreators FsCreators { get; } + private byte[] SdEncryptionSeed { get; } = new byte[0x10]; + + private const string NintendoDirectoryName = "Nintendo"; + private const string ContentDirectoryName = "Contents"; + + public FileSystemProxyCore(FileSystemCreators fsCreators) + { + FsCreators = fsCreators; + } + + public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) + { + return FsCreators.BuiltInStorageFileSystemCreator.Create(out fileSystem, rootPath, partitionId); + } + + public Result OpenSdCardFileSystem(out IFileSystem fileSystem) + { + return FsCreators.SdFileSystemCreator.Create(out fileSystem); + } + + public Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId) + { + fileSystem = default; + + string contentDirPath = default; + IFileSystem baseFileSystem = default; + bool isEncrypted = false; + Result baseFsResult; + + switch (storageId) + { + case ContentStorageId.System: + baseFsResult = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.System); + contentDirPath = $"/{ContentDirectoryName}"; + break; + case ContentStorageId.User: + baseFsResult = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.User); + contentDirPath = $"/{ContentDirectoryName}"; + break; + case ContentStorageId.SdCard: + baseFsResult = OpenSdCardFileSystem(out baseFileSystem); + contentDirPath = $"/{NintendoDirectoryName}/{ContentDirectoryName}"; + isEncrypted = true; + break; + default: + baseFsResult = ResultFs.InvalidArgument; + break; + } + + if (baseFsResult.IsFailure()) return baseFsResult; + + baseFileSystem.EnsureDirectoryExists(contentDirPath); + + Result subFsResult = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFileSystem, + baseFileSystem, contentDirPath); + if (subFsResult.IsFailure()) return subFsResult; + + if (!isEncrypted) + { + fileSystem = subDirFileSystem; + return Result.Success; + } + + return FsCreators.EncryptedFileSystemCreator.Create(out fileSystem, subDirFileSystem, + EncryptedFsKeyId.Content, SdEncryptionSeed); + } + + public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) + { + seed.CopyTo(SdEncryptionSeed); + FsCreators.SaveDataFileSystemCreator.SetSdCardEncryptionSeed(seed); + + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/FileSystemService.cs b/src/LibHac/FsService/FileSystemService.cs new file mode 100644 index 00000000..121cd31e --- /dev/null +++ b/src/LibHac/FsService/FileSystemService.cs @@ -0,0 +1,6 @@ +namespace LibHac.FsService +{ + public class FileSystemService + { + } +} From cb705c5f0fca18ab4cf763bcdbb248076edac843 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 25 Aug 2019 21:41:48 -0500 Subject: [PATCH 04/46] Add some file system creators --- .../Creators/EmulatedBisFileSystemCreator.cs | 99 +++++++++++++++++++ .../EmulatedBisFileSystemCreatorConfig.cs | 73 ++++++++++++++ .../Creators/EmulatedSdFileSystemCreator.cs | 46 +++++++++ .../Creators/EncryptedFileSystemCreator.cs | 33 +++++++ .../FsService/Creators/FileSystemCreators.cs | 16 ++- .../Creators/SubDirectoryFileSystemCreator.cs | 25 +++++ src/LibHac/FsService/FileSystemProxy.cs | 11 +++ src/LibHac/FsService/FileSystemService.cs | 15 ++- src/LibHac/FsService/Util.cs | 47 +++++++++ 9 files changed, 363 insertions(+), 2 deletions(-) create mode 100644 src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs create mode 100644 src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Util.cs diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs new file mode 100644 index 00000000..3f9c4d99 --- /dev/null +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs @@ -0,0 +1,99 @@ +using System.Diagnostics; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class EmulatedBisFileSystemCreator : IBuiltInStorageFileSystemCreator + { + private EmulatedBisFileSystemCreatorConfig Config { get; } + + public EmulatedBisFileSystemCreator(IFileSystem rootFileSystem) + { + Config = new EmulatedBisFileSystemCreatorConfig(); + Config.RootFileSystem = rootFileSystem; + } + + public EmulatedBisFileSystemCreator(EmulatedBisFileSystemCreatorConfig config) + { + Config = config; + } + + public Result Create(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) + { + fileSystem = default; + + if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument; + if (rootPath == null) return ResultFs.NullArgument; + + if (Config.TryGetFileSystem(out fileSystem, partitionId)) + { + return Result.Success; + } + + if (Config.RootFileSystem == null) + { + return ResultFs.PreconditionViolation; + } + + string partitionPath = GetPartitionPath(partitionId); + + Result subFsResult = + Util.CreateSubFileSystem(out IFileSystem subFileSystem, Config.RootFileSystem, partitionPath, true); + + if (subFsResult.IsFailure()) return subFsResult; + + if (rootPath == string.Empty) + { + fileSystem = subFileSystem; + return Result.Success; + } + + return Util.CreateSubFileSystemImpl(out fileSystem, subFileSystem, rootPath); + } + + public Result CreateFatFileSystem(out IFileSystem fileSystem, BisPartitionId partitionId) + { + fileSystem = default; + return ResultFs.NotImplemented; + } + + public Result SetBisRootForHost(BisPartitionId partitionId, string rootPath) + { + return Config.SetPath(rootPath, partitionId); + } + + private bool IsValidPartitionId(BisPartitionId id) + { + return id >= BisPartitionId.CalibrationFile && id <= BisPartitionId.System; + } + + private string GetPartitionPath(BisPartitionId id) + { + if (Config.TryGetPartitionPath(out string path, id)) + { + return path; + } + + return GetDefaultPartitionPath(id); + } + + private string GetDefaultPartitionPath(BisPartitionId id) + { + Debug.Assert(IsValidPartitionId(id)); + + switch (id) + { + case BisPartitionId.CalibrationFile: + return "/bis/cal"; + case BisPartitionId.SafeMode: + return "/bis/safe"; + case BisPartitionId.User: + return "/bis/user"; + case BisPartitionId.System: + return "/bis/system"; + default: + return string.Empty; + } + } + } +} diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs new file mode 100644 index 00000000..1e6ebe98 --- /dev/null +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs @@ -0,0 +1,73 @@ +using System.Diagnostics; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class EmulatedBisFileSystemCreatorConfig + { + private const int ValidPartitionCount = 4; + + public IFileSystem RootFileSystem { get; set; } + + private IFileSystem[] PartitionFileSystems { get; } = new IFileSystem[ValidPartitionCount]; + private string[] PartitionPaths { get; } = new string[ValidPartitionCount]; + + public Result SetFileSystem(IFileSystem fileSystem, BisPartitionId partitionId) + { + if (fileSystem == null) return ResultFs.NullArgument; + if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument; + + PartitionFileSystems[GetArrayIndex(partitionId)] = fileSystem; + + return Result.Success; + } + + public Result SetPath(string path, BisPartitionId partitionId) + { + if (path == null) return ResultFs.NullArgument; + if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument; + + PartitionPaths[GetArrayIndex(partitionId)] = path; + + return Result.Success; + } + + public bool TryGetFileSystem(out IFileSystem fileSystem, BisPartitionId partitionId) + { + if (!IsValidPartitionId(partitionId)) + { + fileSystem = default; + return false; + } + + fileSystem = PartitionFileSystems[GetArrayIndex(partitionId)]; + + return fileSystem != null; + } + + public bool TryGetPartitionPath(out string path, BisPartitionId partitionId) + { + if (!IsValidPartitionId(partitionId)) + { + path = default; + return false; + } + + path = PartitionPaths[GetArrayIndex(partitionId)]; + + return path != null; + } + + private int GetArrayIndex(BisPartitionId id) + { + Debug.Assert(IsValidPartitionId(id)); + + return id - BisPartitionId.CalibrationFile; + } + + private bool IsValidPartitionId(BisPartitionId id) + { + return id >= BisPartitionId.CalibrationFile && id <= BisPartitionId.System; + } + } +} diff --git a/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs new file mode 100644 index 00000000..b27c6aff --- /dev/null +++ b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs @@ -0,0 +1,46 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + class EmulatedSdFileSystemCreator : ISdFileSystemCreator + { + private const string DefaultPath = "/sdcard"; + + public IFileSystem RootFileSystem { get; set; } + public string Path { get; set; } + + public IFileSystem SdCardFileSystem { get; set; } + + public EmulatedSdFileSystemCreator(IFileSystem rootFileSystem) + { + RootFileSystem = rootFileSystem; + } + + public Result Create(out IFileSystem fileSystem) + { + fileSystem = default; + + if (SdCardFileSystem != null) + { + fileSystem = SdCardFileSystem; + + return Result.Success; + } + + if (RootFileSystem == null) + { + return ResultFs.PreconditionViolation; + } + + string path = Path ?? DefaultPath; + + return Util.CreateSubFileSystem(out fileSystem, RootFileSystem, path, true); + } + + public Result Format(bool closeOpenEntries) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs b/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs new file mode 100644 index 00000000..81d5dc4b --- /dev/null +++ b/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs @@ -0,0 +1,33 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator + { + private Keyset Keyset { get; } + + public EncryptedFileSystemCreator(Keyset keyset) + { + Keyset = keyset; + } + + public Result Create(out IFileSystem encryptedFileSystem, IFileSystem baseFileSystem, EncryptedFsKeyId keyId, + ReadOnlySpan encryptionSeed) + { + encryptedFileSystem = default; + + if (keyId < EncryptedFsKeyId.Save || keyId > EncryptedFsKeyId.CustomStorage) + { + return ResultFs.InvalidArgument; + } + + // todo: "proper" key generation instead of a lazy hack + Keyset.SetSdSeed(encryptionSeed.ToArray()); + + encryptedFileSystem = new AesXtsFileSystem(baseFileSystem, Keyset.SdCardKeys[(int)keyId], 0x4000); + + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/Creators/FileSystemCreators.cs b/src/LibHac/FsService/Creators/FileSystemCreators.cs index f38d476c..2ae3114f 100644 --- a/src/LibHac/FsService/Creators/FileSystemCreators.cs +++ b/src/LibHac/FsService/Creators/FileSystemCreators.cs @@ -1,4 +1,6 @@ -namespace LibHac.FsService.Creators +using LibHac.Fs; + +namespace LibHac.FsService.Creators { public class FileSystemCreators { @@ -16,5 +18,17 @@ public IMemoryStorageCreator MemoryStorageCreator { get; set; } public IBuiltInStorageFileSystemCreator BuiltInStorageFileSystemCreator { get; set; } public ISdFileSystemCreator SdFileSystemCreator { get; set; } + + public static FileSystemCreators GetDefaultEmulatedCreators(IFileSystem rootFileSystem, Keyset keyset) + { + var creators = new FileSystemCreators(); + + creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); + creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keyset); + creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem); + creators.SdFileSystemCreator = new EmulatedSdFileSystemCreator(rootFileSystem); + + return creators; + } } } diff --git a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs new file mode 100644 index 00000000..526ffb4e --- /dev/null +++ b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs @@ -0,0 +1,25 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public class SubDirectoryFileSystemCreator : ISubDirectoryFileSystemCreator + { + public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, string path) + { + try + { + baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directories); + } + catch (HorizonResultException ex) + { + subDirFileSystem = default; + + return ex.ResultValue; + } + + subDirFileSystem = new SubdirectoryFileSystem(baseFileSystem, path); + + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index 0b7baf0e..5d61e0be 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -13,6 +13,17 @@ namespace LibHac.FsService public string SaveDataRootPath { get; private set; } public bool AutoCreateSaveData { get; private set; } + internal FileSystemProxy(FileSystemProxyCore fsProxyCore) + { + FsProxyCore = fsProxyCore; + + CurrentProcess = -1; + SaveDataSize = 0x2000000; + SaveDataJournalSize = 0x1000000; + SaveDataRootPath = string.Empty; + AutoCreateSaveData = true; + } + public Result SetCurrentProcess(long processId) { CurrentProcess = processId; diff --git a/src/LibHac/FsService/FileSystemService.cs b/src/LibHac/FsService/FileSystemService.cs index 121cd31e..7597dd3e 100644 --- a/src/LibHac/FsService/FileSystemService.cs +++ b/src/LibHac/FsService/FileSystemService.cs @@ -1,6 +1,19 @@ -namespace LibHac.FsService +using LibHac.FsService.Creators; + +namespace LibHac.FsService { public class FileSystemService { + private FileSystemProxyCore FsProxyCore { get; } + + public FileSystemService(FileSystemCreators fsCreators) + { + FsProxyCore = new FileSystemProxyCore(fsCreators); + } + + public FileSystemProxy CreateFileSystemProxyService() + { + return new FileSystemProxy(FsProxyCore); + } } } diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs new file mode 100644 index 00000000..9ebcab9e --- /dev/null +++ b/src/LibHac/FsService/Util.cs @@ -0,0 +1,47 @@ +using LibHac.Fs; + +namespace LibHac.FsService +{ + public static class Util + { + public static Result CreateSubFileSystem(out IFileSystem subFileSystem, IFileSystem baseFileSystem, string path, + bool createPathIfMissing) + { + subFileSystem = default; + + if (!createPathIfMissing) + { + if (path == null) return ResultFs.NullArgument; + + if (baseFileSystem.GetEntryType(path) != DirectoryEntryType.Directory) + { + return ResultFs.PathNotFound; + } + } + + baseFileSystem.EnsureDirectoryExists(path); + + return CreateSubFileSystemImpl(out subFileSystem, baseFileSystem, path); + } + + public static Result CreateSubFileSystemImpl(out IFileSystem subFileSystem, IFileSystem baseFileSystem, string path) + { + subFileSystem = default; + + if (path == null) return ResultFs.NullArgument; + + try + { + baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directories); + } + catch (HorizonResultException ex) + { + return ex.ResultValue; + } + + subFileSystem = new SubdirectoryFileSystem(baseFileSystem, path); + + return Result.Success; + } + } +} From d610d2262b6e6acc3e9f76f05c7d4c34c128e179 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 27 Aug 2019 12:27:07 -0500 Subject: [PATCH 05/46] Add a Result.Log() method to aid in debugging --- src/LibHac/Result.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/LibHac/Result.cs b/src/LibHac/Result.cs index 86fcb228..86e90ba1 100644 --- a/src/LibHac/Result.cs +++ b/src/LibHac/Result.cs @@ -32,6 +32,17 @@ namespace LibHac } } + /// + /// A function that can contain code for logging or debugging returned results. + /// Intended to be used when returning a non-zero Result: + /// return result.Log(); + /// + /// The called value. + public Result Log() + { + return this; + } + public override bool Equals(object obj) { return obj is Result result && Equals(result); From d6165d1097028e6986924e28e3ccc7c28b0ab81a Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Thu, 29 Aug 2019 18:54:51 -0500 Subject: [PATCH 06/46] Add OpenSaveDataFileSystemBySystemSaveDataId --- src/LibHac/Fs/AesXtsDirectory.cs | 1 + src/LibHac/Fs/FsEnums.cs | 11 ++ src/LibHac/Fs/ResultFs.cs | 3 + .../FsService/Creators/FileSystemCreators.cs | 2 + .../Creators/IHostFileSystemCreator.cs | 10 ++ .../ITargetManagerFileSystemCreator.cs | 10 ++ src/LibHac/FsService/FileSystemProxy.cs | 61 ++++++++- src/LibHac/FsService/FileSystemProxyCore.cs | 123 +++++++++++++++++- src/LibHac/FsService/IFileSystemProxy.cs | 20 +++ src/LibHac/FsService/Util.cs | 9 ++ 10 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 src/LibHac/FsService/Creators/IHostFileSystemCreator.cs create mode 100644 src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs create mode 100644 src/LibHac/FsService/IFileSystemProxy.cs diff --git a/src/LibHac/Fs/AesXtsDirectory.cs b/src/LibHac/Fs/AesXtsDirectory.cs index 99caa17a..e3400a65 100644 --- a/src/LibHac/Fs/AesXtsDirectory.cs +++ b/src/LibHac/Fs/AesXtsDirectory.cs @@ -33,6 +33,7 @@ namespace LibHac.Fs } else { + // todo: FS returns invalid file entries with a size of 0 long size = GetAesXtsFileSize(entry.FullPath); if (size == -1) continue; diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs index d5f09439..edb8f0b2 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -42,4 +42,15 @@ Secure = 1, Writable = 2 } + + public enum SaveDataSpaceId + { + System = 0, + User = 1, + SdSystem = 2, + TemporaryStorage = 3, + SdCache = 4, + ProperSystem = 100, + Safe = 101 + } } diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 549f5d60..4cc73c86 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -11,6 +11,9 @@ public static Result InsufficientFreeSpace => new Result(ModuleFs, 30); public static Result MountNameAlreadyExists => new Result(ModuleFs, 60); + public static Result ResultPartitionNotFound => new Result(ModuleFs, 1002); + public static Result TargetNotFound => new Result(ModuleFs, 1002); + public static Result NotImplemented => new Result(ModuleFs, 3001); public static Result Result3002 => new Result(ModuleFs, 3002); public static Result SaveDataPathAlreadyExists => new Result(ModuleFs, 3003); diff --git a/src/LibHac/FsService/Creators/FileSystemCreators.cs b/src/LibHac/FsService/Creators/FileSystemCreators.cs index 2ae3114f..2afa63df 100644 --- a/src/LibHac/FsService/Creators/FileSystemCreators.cs +++ b/src/LibHac/FsService/Creators/FileSystemCreators.cs @@ -8,6 +8,8 @@ namespace LibHac.FsService.Creators public IPartitionFileSystemCreator PartitionFileSystemCreator { get; set; } public IStorageOnNcaCreator StorageOnNcaCreator { get; set; } public IFatFileSystemCreator FatFileSystemCreator { get; set; } + public IHostFileSystemCreator HostFileSystemCreator { get; set; } + public ITargetManagerFileSystemCreator TargetManagerFileSystemCreator { get; set; } public ISubDirectoryFileSystemCreator SubDirectoryFileSystemCreator { get; set; } public IBuiltInStorageCreator BuiltInStorageCreator { get; set; } public ISdStorageCreator SdStorageCreator { get; set; } diff --git a/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs new file mode 100644 index 00000000..f00dde73 --- /dev/null +++ b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs @@ -0,0 +1,10 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface IHostFileSystemCreator + { + Result Create(out IFileSystem fileSystem, bool someBool); + Result Create(out IFileSystem fileSystem, string path, bool someBool); + } +} \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs new file mode 100644 index 00000000..7de7c485 --- /dev/null +++ b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs @@ -0,0 +1,10 @@ +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + public interface ITargetManagerFileSystemCreator + { + Result Create(out IFileSystem fileSystem, bool someBool); + Result GetCaseSensitivePath(out bool isSuccess, ref string path); + } +} \ No newline at end of file diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index 5d61e0be..6e5b675b 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsService @@ -13,6 +14,8 @@ namespace LibHac.FsService public string SaveDataRootPath { get; private set; } public bool AutoCreateSaveData { get; private set; } + private const ulong SaveIndexerId = 0x8000000000000000; + internal FileSystemProxy(FileSystemProxyCore fsProxyCore) { FsProxyCore = fsProxyCore; @@ -86,10 +89,29 @@ namespace LibHac.FsService return FsProxyCore.OpenContentStorageFileSystem(out fileSystem, storageId); } + public Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, + SaveDataAttribute attribute) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + fileSystem = default; + + if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log(); + + Result saveFsResult = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out ulong saveDataId, spaceId, + attribute, false, true); + if (saveFsResult.IsFailure()) return saveFsResult.Log(); + + // Missing check if the current title owns the save data or can open it + + fileSystem = saveFs; + + return Result.Success; + } + public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) { // todo: use struct instead of byte span - if (seed.Length != 0x16) return ResultFs.InvalidSize; + if (seed.Length != 0x10) return ResultFs.InvalidSize; // Missing permission check @@ -100,5 +122,42 @@ namespace LibHac.FsService return Result.Success; } + + private Result OpenSaveDataFileSystemImpl(out IFileSystem fileSystem, out ulong saveDataId, + SaveDataSpaceId spaceId, SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData) + { + bool hasFixedId = attribute.SaveId != 0 && attribute.UserId.Id == Id128.InvalidId; + + if (hasFixedId) + { + saveDataId = attribute.SaveId; + } + else + { + throw new NotImplementedException(); + } + + Result saveFsResult = FsProxyCore.OpenSaveDataFileSystem(out fileSystem, spaceId, saveDataId, + SaveDataRootPath, openReadOnly, attribute.Type, cacheExtraData); + + if (saveFsResult.IsSuccess()) return Result.Success; + + if (saveFsResult == ResultFs.PathNotFound || saveFsResult == ResultFs.TargetNotFound) return saveFsResult; + + if (saveDataId != SaveIndexerId) + { + if(hasFixedId) + { + // todo: remove save indexer entry + } + } + + return ResultFs.TargetNotFound; + } + + private bool IsSystemSaveDataId(ulong id) + { + return (long)id < 0; + } } } diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 25c486c0..6f1a67a7 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -1,5 +1,6 @@ using System; using LibHac.Fs; +using LibHac.Fs.Save; using LibHac.FsService.Creators; namespace LibHac.FsService @@ -77,9 +78,129 @@ namespace LibHac.FsService public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) { seed.CopyTo(SdEncryptionSeed); - FsCreators.SaveDataFileSystemCreator.SetSdCardEncryptionSeed(seed); + //FsCreators.SaveDataFileSystemCreator.SetSdCardEncryptionSeed(seed); return Result.Success; } + + public bool AllowDirectorySaveData(SaveDataSpaceId spaceId, string saveDataRootPath) + { + return spaceId == SaveDataSpaceId.User && !string.IsNullOrWhiteSpace(saveDataRootPath); + } + + public Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ulong saveDataId, + string saveDataRootPath, bool openReadOnly, SaveDataType type, bool cacheExtraData) + { + fileSystem = default; + + Result openSaveDirResult = OpenSaveDataDirectory(out IFileSystem saveDirFs, spaceId, saveDataRootPath, true); + if (openSaveDirResult.IsFailure()) return openSaveDirResult.Log(); + + bool allowDirectorySaveData = AllowDirectorySaveData(spaceId, saveDataRootPath); + bool useDeviceUniqueMac = Util.UseDeviceUniqueSaveMac(spaceId); + + if (allowDirectorySaveData) + { + try + { + saveDirFs.EnsureDirectoryExists(GetSaveDataIdPath(saveDataId)); + } + catch (HorizonResultException ex) + { + return ex.ResultValue; + } + } + + // Missing save FS cache lookup + + Result saveFsResult = FsCreators.SaveDataFileSystemCreator.Create(out IFileSystem saveFs, + out ISaveDataExtraDataAccessor extraDataAccessor, saveDirFs, saveDataId, allowDirectorySaveData, + useDeviceUniqueMac, type, null); + + if (saveFsResult.IsFailure()) return saveFsResult.Log(); + + if (cacheExtraData) + { + // Missing extra data caching + } + + fileSystem = openReadOnly ? new ReadOnlyFileSystem(saveFs) : saveFs; + + return Result.Success; + } + + public Result OpenSaveDataDirectory(out IFileSystem fileSystem, SaveDataSpaceId spaceId, string saveDataRootPath, bool openOnHostFs) + { + if (openOnHostFs && AllowDirectorySaveData(spaceId, saveDataRootPath)) + { + Result hostFsResult = FsCreators.TargetManagerFileSystemCreator.Create(out IFileSystem hostFs, false); + + if (hostFsResult.IsFailure()) + { + fileSystem = default; + return hostFsResult.Log(); + } + + return Util.CreateSubFileSystem(out fileSystem, hostFs, saveDataRootPath, true); + } + + string dirName = spaceId == SaveDataSpaceId.TemporaryStorage ? "/temp" : "/save"; + + return OpenSaveDataDirectoryImpl(out fileSystem, spaceId, dirName, true); + } + + public Result OpenSaveDataDirectoryImpl(out IFileSystem fileSystem, SaveDataSpaceId spaceId, string saveDirName, bool createIfMissing) + { + fileSystem = default; + + switch (spaceId) + { + case SaveDataSpaceId.System: + Result sysFsResult = OpenBisFileSystem(out IFileSystem sysFs, string.Empty, BisPartitionId.System); + if (sysFsResult.IsFailure()) return sysFsResult.Log(); + + return Util.CreateSubFileSystem(out fileSystem, sysFs, saveDirName, createIfMissing); + + case SaveDataSpaceId.User: + case SaveDataSpaceId.TemporaryStorage: + Result userFsResult = OpenBisFileSystem(out IFileSystem userFs, string.Empty, BisPartitionId.System); + if (userFsResult.IsFailure()) return userFsResult.Log(); + + return Util.CreateSubFileSystem(out fileSystem, userFs, saveDirName, createIfMissing); + + case SaveDataSpaceId.SdSystem: + case SaveDataSpaceId.SdCache: + Result sdFsResult = OpenSdCardFileSystem(out IFileSystem sdFs); + if (sdFsResult.IsFailure()) return sdFsResult.Log(); + + string sdSaveDirPath = $"/{NintendoDirectoryName}{saveDirName}"; + + Result sdSubResult = Util.CreateSubFileSystem(out IFileSystem sdSubFs, sdFs, sdSaveDirPath, createIfMissing); + if (sdSubResult.IsFailure()) return sdSubResult.Log(); + + return FsCreators.EncryptedFileSystemCreator.Create(out fileSystem, sdSubFs, + EncryptedFsKeyId.Save, SdEncryptionSeed); + + case SaveDataSpaceId.ProperSystem: + Result sysProperFsResult = OpenBisFileSystem(out IFileSystem sysProperFs, string.Empty, BisPartitionId.SystemProperPartition); + if (sysProperFsResult.IsFailure()) return sysProperFsResult.Log(); + + return Util.CreateSubFileSystem(out fileSystem, sysProperFs, saveDirName, createIfMissing); + + case SaveDataSpaceId.Safe: + Result safeFsResult = OpenBisFileSystem(out IFileSystem safeFs, string.Empty, BisPartitionId.SafeMode); + if (safeFsResult.IsFailure()) return safeFsResult.Log(); + + return Util.CreateSubFileSystem(out fileSystem, safeFs, saveDirName, createIfMissing); + + default: + return ResultFs.InvalidArgument.Log(); + } + } + + private string GetSaveDataIdPath(ulong saveDataId) + { + return $"/{saveDataId:x16}"; + } } } diff --git a/src/LibHac/FsService/IFileSystemProxy.cs b/src/LibHac/FsService/IFileSystemProxy.cs new file mode 100644 index 00000000..cd3ac661 --- /dev/null +++ b/src/LibHac/FsService/IFileSystemProxy.cs @@ -0,0 +1,20 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService +{ + public interface IFileSystemProxy + { + Result SetCurrentProcess(long processId); + Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId); + Result OpenSdCardFileSystem(out IFileSystem fileSystem); + Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId); + Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute); + Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute); + Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId); + Result SetSdCardEncryptionSeed(ReadOnlySpan seed); + Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); + Result SetSaveDataRootPath(string path); + Result DisableAutoSaveDataCreation(); + } +} \ No newline at end of file diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs index 9ebcab9e..3b151c1e 100644 --- a/src/LibHac/FsService/Util.cs +++ b/src/LibHac/FsService/Util.cs @@ -43,5 +43,14 @@ namespace LibHac.FsService return Result.Success; } + + public static bool UseDeviceUniqueSaveMac(SaveDataSpaceId spaceId) + { + return spaceId == SaveDataSpaceId.System || + spaceId == SaveDataSpaceId.User || + spaceId == SaveDataSpaceId.TemporaryStorage || + spaceId == SaveDataSpaceId.ProperSystem || + spaceId == SaveDataSpaceId.Safe; + } } } From dfff3b1ccf018cf4e673f9b3a9f312c90e9057bc Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 31 Aug 2019 10:15:49 -0500 Subject: [PATCH 07/46] Create FileSystemClient --- .../Accessors/DirectoryAccessor.cs | 3 +- .../Accessors/DirectoryHandle.cs | 2 +- .../Accessors/FileAccessor.cs | 3 +- .../{Fs => FsClient}/Accessors/FileHandle.cs | 2 +- .../Accessors/FileSystemAccessor.cs | 3 +- .../{Fs => FsClient}/Accessors/MountTable.cs | 3 +- src/LibHac/FsClient/FileSystemClient.cs | 33 +++++++++++ .../{Fs => FsClient}/FileSystemManager.cs | 10 +++- .../FileSystemManagerUtils.cs | 5 +- .../{Fs/Accessors => FsClient}/IAccessLog.cs | 2 +- src/LibHac/FsClient/SdCardAccessLog.cs | 16 ++++++ src/LibHac/FsService/FileSystemProxy.cs | 10 +++- src/LibHac/FsService/FileSystemServer.cs | 55 +++++++++++++++++++ src/LibHac/FsService/FileSystemService.cs | 19 ------- src/LibHac/Horizon.cs | 18 +++++- .../StopWatchTimeSpanGenerator.cs} | 5 +- src/hactoolnet/AccessLog.cs | 2 +- src/hactoolnet/FsUtils.cs | 3 +- src/hactoolnet/ProcessNca.cs | 1 + src/hactoolnet/ProcessSave.cs | 1 + 20 files changed, 158 insertions(+), 38 deletions(-) rename src/LibHac/{Fs => FsClient}/Accessors/DirectoryAccessor.cs (95%) rename src/LibHac/{Fs => FsClient}/Accessors/DirectoryHandle.cs (92%) rename src/LibHac/{Fs => FsClient}/Accessors/FileAccessor.cs (97%) rename src/LibHac/{Fs => FsClient}/Accessors/FileHandle.cs (91%) rename src/LibHac/{Fs => FsClient}/Accessors/FileSystemAccessor.cs (98%) rename src/LibHac/{Fs => FsClient}/Accessors/MountTable.cs (96%) create mode 100644 src/LibHac/FsClient/FileSystemClient.cs rename src/LibHac/{Fs => FsClient}/FileSystemManager.cs (99%) rename src/LibHac/{Fs => FsClient}/FileSystemManagerUtils.cs (98%) rename src/LibHac/{Fs/Accessors => FsClient}/IAccessLog.cs (88%) create mode 100644 src/LibHac/FsClient/SdCardAccessLog.cs create mode 100644 src/LibHac/FsService/FileSystemServer.cs delete mode 100644 src/LibHac/FsService/FileSystemService.cs rename src/{hactoolnet/TimeSpanTimer.cs => LibHac/StopWatchTimeSpanGenerator.cs} (70%) diff --git a/src/LibHac/Fs/Accessors/DirectoryAccessor.cs b/src/LibHac/FsClient/Accessors/DirectoryAccessor.cs similarity index 95% rename from src/LibHac/Fs/Accessors/DirectoryAccessor.cs rename to src/LibHac/FsClient/Accessors/DirectoryAccessor.cs index e3b3141e..94df1121 100644 --- a/src/LibHac/Fs/Accessors/DirectoryAccessor.cs +++ b/src/LibHac/FsClient/Accessors/DirectoryAccessor.cs @@ -1,7 +1,8 @@ using System; using System.Collections.Generic; +using LibHac.Fs; -namespace LibHac.Fs.Accessors +namespace LibHac.FsClient.Accessors { public class DirectoryAccessor : IDisposable { diff --git a/src/LibHac/Fs/Accessors/DirectoryHandle.cs b/src/LibHac/FsClient/Accessors/DirectoryHandle.cs similarity index 92% rename from src/LibHac/Fs/Accessors/DirectoryHandle.cs rename to src/LibHac/FsClient/Accessors/DirectoryHandle.cs index d4804306..05f8fb67 100644 --- a/src/LibHac/Fs/Accessors/DirectoryHandle.cs +++ b/src/LibHac/FsClient/Accessors/DirectoryHandle.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs.Accessors +namespace LibHac.FsClient.Accessors { public struct DirectoryHandle : IDisposable { diff --git a/src/LibHac/Fs/Accessors/FileAccessor.cs b/src/LibHac/FsClient/Accessors/FileAccessor.cs similarity index 97% rename from src/LibHac/Fs/Accessors/FileAccessor.cs rename to src/LibHac/FsClient/Accessors/FileAccessor.cs index a269f639..f69bec1f 100644 --- a/src/LibHac/Fs/Accessors/FileAccessor.cs +++ b/src/LibHac/FsClient/Accessors/FileAccessor.cs @@ -1,6 +1,7 @@ using System; +using LibHac.Fs; -namespace LibHac.Fs.Accessors +namespace LibHac.FsClient.Accessors { public class FileAccessor : IFile { diff --git a/src/LibHac/Fs/Accessors/FileHandle.cs b/src/LibHac/FsClient/Accessors/FileHandle.cs similarity index 91% rename from src/LibHac/Fs/Accessors/FileHandle.cs rename to src/LibHac/FsClient/Accessors/FileHandle.cs index da454f4d..df7c8fa4 100644 --- a/src/LibHac/Fs/Accessors/FileHandle.cs +++ b/src/LibHac/FsClient/Accessors/FileHandle.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs.Accessors +namespace LibHac.FsClient.Accessors { public struct FileHandle : IDisposable { diff --git a/src/LibHac/Fs/Accessors/FileSystemAccessor.cs b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs similarity index 98% rename from src/LibHac/Fs/Accessors/FileSystemAccessor.cs rename to src/LibHac/FsClient/Accessors/FileSystemAccessor.cs index 3e8293fd..391f7381 100644 --- a/src/LibHac/Fs/Accessors/FileSystemAccessor.cs +++ b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using LibHac.Fs; -namespace LibHac.Fs.Accessors +namespace LibHac.FsClient.Accessors { public class FileSystemAccessor { diff --git a/src/LibHac/Fs/Accessors/MountTable.cs b/src/LibHac/FsClient/Accessors/MountTable.cs similarity index 96% rename from src/LibHac/Fs/Accessors/MountTable.cs rename to src/LibHac/FsClient/Accessors/MountTable.cs index ec9f94cb..de87b56e 100644 --- a/src/LibHac/Fs/Accessors/MountTable.cs +++ b/src/LibHac/FsClient/Accessors/MountTable.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using LibHac.Fs; -namespace LibHac.Fs.Accessors +namespace LibHac.FsClient.Accessors { public class MountTable { diff --git a/src/LibHac/FsClient/FileSystemClient.cs b/src/LibHac/FsClient/FileSystemClient.cs new file mode 100644 index 00000000..9076769a --- /dev/null +++ b/src/LibHac/FsClient/FileSystemClient.cs @@ -0,0 +1,33 @@ +using LibHac.FsService; + +namespace LibHac.FsClient +{ + public class FileSystemClient + { + private FileSystemServer FsSrv { get; } + private FileSystemProxy FsProxy { get; set; } + private FileSystemManager FsManager { get; } + + private readonly object _fspInitLocker = new object(); + + public FileSystemClient(FileSystemServer fsServer, ITimeSpanGenerator timer) + { + FsSrv = fsServer; + FsManager = new FileSystemManager(timer); + } + + private FileSystemProxy GetFileSystemProxyServiceObject() + { + if (FsProxy != null) return FsProxy; + + lock (_fspInitLocker) + { + if (FsProxy != null) return FsProxy; + + FsProxy = FsSrv.CreateFileSystemProxyService(); + + return FsProxy; + } + } + } +} diff --git a/src/LibHac/Fs/FileSystemManager.cs b/src/LibHac/FsClient/FileSystemManager.cs similarity index 99% rename from src/LibHac/Fs/FileSystemManager.cs rename to src/LibHac/FsClient/FileSystemManager.cs index 973ce264..ecd228d0 100644 --- a/src/LibHac/Fs/FileSystemManager.cs +++ b/src/LibHac/FsClient/FileSystemManager.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; -using LibHac.Fs.Accessors; +using LibHac.Fs; +using LibHac.FsClient.Accessors; -namespace LibHac.Fs +namespace LibHac.FsClient { public class FileSystemManager { @@ -26,6 +27,11 @@ namespace LibHac.Fs Time = timer; } + public FileSystemManager(ITimeSpanGenerator timer) + { + Time = timer; + } + public void Register(string mountName, IFileSystem fileSystem) { var accessor = new FileSystemAccessor(mountName, fileSystem, this); diff --git a/src/LibHac/Fs/FileSystemManagerUtils.cs b/src/LibHac/FsClient/FileSystemManagerUtils.cs similarity index 98% rename from src/LibHac/Fs/FileSystemManagerUtils.cs rename to src/LibHac/FsClient/FileSystemManagerUtils.cs index 7e0498f7..5cdd0807 100644 --- a/src/LibHac/Fs/FileSystemManagerUtils.cs +++ b/src/LibHac/FsClient/FileSystemManagerUtils.cs @@ -1,9 +1,10 @@ using System; using System.Buffers; using System.Collections.Generic; -using LibHac.Fs.Accessors; +using LibHac.Fs; +using LibHac.FsClient.Accessors; -namespace LibHac.Fs +namespace LibHac.FsClient { public static class FileSystemManagerUtils { diff --git a/src/LibHac/Fs/Accessors/IAccessLog.cs b/src/LibHac/FsClient/IAccessLog.cs similarity index 88% rename from src/LibHac/Fs/Accessors/IAccessLog.cs rename to src/LibHac/FsClient/IAccessLog.cs index 3ff9ed53..b145e32f 100644 --- a/src/LibHac/Fs/Accessors/IAccessLog.cs +++ b/src/LibHac/FsClient/IAccessLog.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.CompilerServices; -namespace LibHac.Fs.Accessors +namespace LibHac.FsClient { public interface IAccessLog { diff --git a/src/LibHac/FsClient/SdCardAccessLog.cs b/src/LibHac/FsClient/SdCardAccessLog.cs new file mode 100644 index 00000000..d3b97ae9 --- /dev/null +++ b/src/LibHac/FsClient/SdCardAccessLog.cs @@ -0,0 +1,16 @@ +using System; +using LibHac.FsService; + +namespace LibHac.FsClient +{ + /// + /// The default access logger that will output to the SD card via . + /// + public class SdCardAccessLog : IAccessLog + { + public void Log(TimeSpan startTime, TimeSpan endTime, int handleId, string message, string caller = "") + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index 6e5b675b..f43fca19 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -1,12 +1,17 @@ using System; using LibHac.Common; using LibHac.Fs; +using LibHac.FsClient; namespace LibHac.FsService { public class FileSystemProxy { private FileSystemProxyCore FsProxyCore { get; } + + /// The client instance to be used for internal operations like save indexer access. + private FileSystemClient FsClient { get; } + public long CurrentProcess { get; private set; } public long SaveDataSize { get; private set; } @@ -16,9 +21,10 @@ namespace LibHac.FsService private const ulong SaveIndexerId = 0x8000000000000000; - internal FileSystemProxy(FileSystemProxyCore fsProxyCore) + internal FileSystemProxy(FileSystemProxyCore fsProxyCore, FileSystemClient fsClient) { FsProxyCore = fsProxyCore; + FsClient = fsClient; CurrentProcess = -1; SaveDataSize = 0x2000000; @@ -146,7 +152,7 @@ namespace LibHac.FsService if (saveDataId != SaveIndexerId) { - if(hasFixedId) + if (hasFixedId) { // todo: remove save indexer entry } diff --git a/src/LibHac/FsService/FileSystemServer.cs b/src/LibHac/FsService/FileSystemServer.cs new file mode 100644 index 00000000..974a8f34 --- /dev/null +++ b/src/LibHac/FsService/FileSystemServer.cs @@ -0,0 +1,55 @@ +using LibHac.FsClient; +using LibHac.FsService.Creators; + +namespace LibHac.FsService +{ + public class FileSystemServer + { + private FileSystemProxyCore FsProxyCore { get; } + + /// The client instance to be used for internal operations like save indexer access. + private FileSystemClient FsClient { get; } + private ITimeSpanGenerator Timer { get; } + + /// + /// Creates a new with a new default . + /// + /// The used for creating filesystems. + public FileSystemServer(FileSystemCreators fsCreators) : this(fsCreators, new StopWatchTimeSpanGenerator()) { } + + /// + /// Creates a new . + /// + /// The used for creating filesystems. + /// The to use for access log timestamps. + public FileSystemServer(FileSystemCreators fsCreators, ITimeSpanGenerator timer) + { + FsProxyCore = new FileSystemProxyCore(fsCreators); + FsClient = new FileSystemClient(this, timer); + Timer = timer; + } + + /// + /// Creates a new using this 's + /// for the client's access log. + /// + /// The created . + public FileSystemClient CreateFileSystemClient() => CreateFileSystemClient(Timer); + + /// + /// Creates a new . + /// + /// The to use for the created + /// 's access log. + /// The created . + public FileSystemClient CreateFileSystemClient(ITimeSpanGenerator timer) + { + return new FileSystemClient(this, timer); + } + + public FileSystemProxy CreateFileSystemProxyService() + { + return new FileSystemProxy(FsProxyCore, FsClient); + } + } +} diff --git a/src/LibHac/FsService/FileSystemService.cs b/src/LibHac/FsService/FileSystemService.cs deleted file mode 100644 index 7597dd3e..00000000 --- a/src/LibHac/FsService/FileSystemService.cs +++ /dev/null @@ -1,19 +0,0 @@ -using LibHac.FsService.Creators; - -namespace LibHac.FsService -{ - public class FileSystemService - { - private FileSystemProxyCore FsProxyCore { get; } - - public FileSystemService(FileSystemCreators fsCreators) - { - FsProxyCore = new FileSystemProxyCore(fsCreators); - } - - public FileSystemProxy CreateFileSystemProxyService() - { - return new FileSystemProxy(FsProxyCore); - } - } -} diff --git a/src/LibHac/Horizon.cs b/src/LibHac/Horizon.cs index 6e55025d..370dc5b2 100644 --- a/src/LibHac/Horizon.cs +++ b/src/LibHac/Horizon.cs @@ -1,4 +1,6 @@ -using LibHac.Fs; +using LibHac.FsClient; +using LibHac.FsService; +using LibHac.FsService.Creators; namespace LibHac { @@ -7,6 +9,9 @@ namespace LibHac internal ITimeSpanGenerator Time { get; } public FileSystemManager Fs { get; } + public FileSystemServer FsSrv { get; private set; } + + private readonly object _initLocker = new object(); public Horizon() { @@ -19,5 +24,16 @@ namespace LibHac Fs = new FileSystemManager(this, timer); } + + public void InitializeFileSystemServer(FileSystemCreators fsCreators) + { + if (FsSrv != null) return; + + lock (_initLocker) + { + if (FsSrv != null) return; + FsSrv = new FileSystemServer(fsCreators); + } + } } } diff --git a/src/hactoolnet/TimeSpanTimer.cs b/src/LibHac/StopWatchTimeSpanGenerator.cs similarity index 70% rename from src/hactoolnet/TimeSpanTimer.cs rename to src/LibHac/StopWatchTimeSpanGenerator.cs index 9235181d..c10e9da2 100644 --- a/src/hactoolnet/TimeSpanTimer.cs +++ b/src/LibHac/StopWatchTimeSpanGenerator.cs @@ -1,10 +1,9 @@ using System; using System.Diagnostics; -using LibHac; -namespace hactoolnet +namespace LibHac { - public class TimeSpanTimer : ITimeSpanGenerator + public class StopWatchTimeSpanGenerator : ITimeSpanGenerator { private Stopwatch Timer = Stopwatch.StartNew(); diff --git a/src/hactoolnet/AccessLog.cs b/src/hactoolnet/AccessLog.cs index 89226520..f7f505c0 100644 --- a/src/hactoolnet/AccessLog.cs +++ b/src/hactoolnet/AccessLog.cs @@ -2,7 +2,7 @@ using System.IO; using System.Runtime.CompilerServices; using LibHac; -using LibHac.Fs.Accessors; +using LibHac.FsClient; namespace hactoolnet { diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index 6ece0c28..eb752b27 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -2,7 +2,8 @@ using System.Buffers; using LibHac; using LibHac.Fs; -using LibHac.Fs.Accessors; +using LibHac.FsClient; +using LibHac.FsClient.Accessors; namespace hactoolnet { diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index 7f644940..f7b7f09d 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -3,6 +3,7 @@ using System.Text; using LibHac; using LibHac.Fs; using LibHac.Fs.NcaUtils; +using LibHac.FsClient; using LibHac.Npdm; using static hactoolnet.Print; diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index 349a6dc7..c973401f 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -6,6 +6,7 @@ using System.Text; using LibHac; using LibHac.Fs; using LibHac.Fs.Save; +using LibHac.FsClient; using static hactoolnet.Print; namespace hactoolnet From f0ce5a994692ee1ec1bc0eff3c9661f0b676e940 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 31 Aug 2019 19:17:28 -0500 Subject: [PATCH 08/46] Change names of some enum members --- src/LibHac/Fs/ConcatenationDirectory.cs | 4 ++-- src/LibHac/Fs/ConcatenationFileSystem.cs | 2 +- src/LibHac/Fs/FileBase.cs | 4 ++-- src/LibHac/Fs/FileSystemExtensions.cs | 6 +++--- src/LibHac/Fs/IFile.cs | 2 +- src/LibHac/Fs/IFileSystem.cs | 6 +++--- src/LibHac/Fs/LocalDirectory.cs | 4 ++-- src/LibHac/Fs/PartitionDirectory.cs | 4 ++-- src/LibHac/Fs/PartitionFileSystemBuilder.cs | 2 +- src/LibHac/Fs/RomFs/RomFsDirectory.cs | 8 ++++---- src/LibHac/Fs/Save/SaveDataDirectory.cs | 8 ++++---- src/LibHac/FsClient/FileSystemManagerUtils.cs | 2 +- .../FsService/Creators/SubDirectoryFileSystemCreator.cs | 2 +- src/LibHac/FsService/Util.cs | 2 +- src/hactoolnet/FsUtils.cs | 2 +- src/hactoolnet/Program.cs | 2 +- 16 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/LibHac/Fs/ConcatenationDirectory.cs b/src/LibHac/Fs/ConcatenationDirectory.cs index 770563f1..90718113 100644 --- a/src/LibHac/Fs/ConcatenationDirectory.cs +++ b/src/LibHac/Fs/ConcatenationDirectory.cs @@ -58,8 +58,8 @@ namespace LibHac.Fs private bool CanReturnEntry(DirectoryEntry entry, bool isSplit) { - return Mode.HasFlag(OpenDirectoryMode.Files) && (entry.Type == DirectoryEntryType.File || isSplit) || - Mode.HasFlag(OpenDirectoryMode.Directories) && entry.Type == DirectoryEntryType.Directory && !isSplit; + return Mode.HasFlag(OpenDirectoryMode.File) && (entry.Type == DirectoryEntryType.File || isSplit) || + Mode.HasFlag(OpenDirectoryMode.Directory) && entry.Type == DirectoryEntryType.Directory && !isSplit; } private bool IsConcatenationFile(DirectoryEntry entry) diff --git a/src/LibHac/Fs/ConcatenationFileSystem.cs b/src/LibHac/Fs/ConcatenationFileSystem.cs index fb242849..f9df0964 100644 --- a/src/LibHac/Fs/ConcatenationFileSystem.cs +++ b/src/LibHac/Fs/ConcatenationFileSystem.cs @@ -72,7 +72,7 @@ namespace LibHac.Fs if (BaseFileSystem.GetEntryType(PathTools.Combine(path, "00")) != DirectoryEntryType.File) return false; - if (BaseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directories).GetEntryCount() > 0) return false; + if (BaseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directory).GetEntryCount() > 0) return false; // Should be enough checks to avoid most false positives. Maybe return true; diff --git a/src/LibHac/Fs/FileBase.cs b/src/LibHac/Fs/FileBase.cs index aae12e8d..d84b30d4 100644 --- a/src/LibHac/Fs/FileBase.cs +++ b/src/LibHac/Fs/FileBase.cs @@ -46,7 +46,7 @@ namespace LibHac.Fs if (offset + size > fileSize) { - if ((Mode & OpenMode.Append) == 0) + if ((Mode & OpenMode.AllowAppend) == 0) { ThrowHelper.ThrowResult(ResultFs.AllowAppendRequiredForImplicitExtension); } @@ -87,7 +87,7 @@ namespace LibHac.Fs { Read = 1, Write = 2, - Append = 4, + AllowAppend = 4, ReadWrite = Read | Write } diff --git a/src/LibHac/Fs/FileSystemExtensions.cs b/src/LibHac/Fs/FileSystemExtensions.cs index cc88706b..8669d230 100644 --- a/src/LibHac/Fs/FileSystemExtensions.cs +++ b/src/LibHac/Fs/FileSystemExtensions.cs @@ -31,7 +31,7 @@ namespace LibHac.Fs destFs.CreateOrOverwriteFile(subDstPath, entry.Size, options); using (IFile srcFile = sourceFs.OpenFile(subSrcPath, OpenMode.Read)) - using (IFile dstFile = destFs.OpenFile(subDstPath, OpenMode.Write | OpenMode.Append)) + using (IFile dstFile = destFs.OpenFile(subDstPath, OpenMode.Write | OpenMode.AllowAppend)) { logger?.LogMessage(subSrcPath); srcFile.CopyTo(dstFile, logger); @@ -142,8 +142,8 @@ namespace LibHac.Fs foreach (DirectoryEntry entry in directory.EnumerateEntries()) { - if (entry.Type == DirectoryEntryType.Directory && (mode & OpenDirectoryMode.Directories) != 0 || - entry.Type == DirectoryEntryType.File && (mode & OpenDirectoryMode.Files) != 0) + if (entry.Type == DirectoryEntryType.Directory && (mode & OpenDirectoryMode.Directory) != 0 || + entry.Type == DirectoryEntryType.File && (mode & OpenDirectoryMode.File) != 0) { count++; } diff --git a/src/LibHac/Fs/IFile.cs b/src/LibHac/Fs/IFile.cs index 22bef0bf..ad4136f9 100644 --- a/src/LibHac/Fs/IFile.cs +++ b/src/LibHac/Fs/IFile.cs @@ -14,7 +14,7 @@ namespace LibHac.Fs /// or write as many bytes as it can and return that number of bytes to the caller. /// /// - If is called on an offset past the end of the , - /// the mode is set and the file supports expansion, + /// the mode is set and the file supports expansion, /// the file will be expanded so that it is large enough to contain the written data. public interface IFile : IDisposable { diff --git a/src/LibHac/Fs/IFileSystem.cs b/src/LibHac/Fs/IFileSystem.cs index 827d2f15..dc62fb24 100644 --- a/src/LibHac/Fs/IFileSystem.cs +++ b/src/LibHac/Fs/IFileSystem.cs @@ -204,9 +204,9 @@ namespace LibHac.Fs [Flags] public enum OpenDirectoryMode { - Directories = 1, - Files = 2, - All = Directories | Files + Directory = 1, + File = 2, + All = Directory | File } /// diff --git a/src/LibHac/Fs/LocalDirectory.cs b/src/LibHac/Fs/LocalDirectory.cs index be1069b7..3086be3b 100644 --- a/src/LibHac/Fs/LocalDirectory.cs +++ b/src/LibHac/Fs/LocalDirectory.cs @@ -73,8 +73,8 @@ namespace LibHac.Fs [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool CanReturnEntry(bool isDir, OpenDirectoryMode mode) { - return isDir && (mode & OpenDirectoryMode.Directories) != 0 || - !isDir && (mode & OpenDirectoryMode.Files) != 0; + return isDir && (mode & OpenDirectoryMode.Directory) != 0 || + !isDir && (mode & OpenDirectoryMode.File) != 0; } } } diff --git a/src/LibHac/Fs/PartitionDirectory.cs b/src/LibHac/Fs/PartitionDirectory.cs index 99dc6102..dc6e4db1 100644 --- a/src/LibHac/Fs/PartitionDirectory.cs +++ b/src/LibHac/Fs/PartitionDirectory.cs @@ -25,7 +25,7 @@ namespace LibHac.Fs public IEnumerable Read() { - if (Mode.HasFlag(OpenDirectoryMode.Files)) + if (Mode.HasFlag(OpenDirectoryMode.File)) { foreach (PartitionFileEntry entry in ParentFileSystem.Files) { @@ -38,7 +38,7 @@ namespace LibHac.Fs { int count = 0; - if (Mode.HasFlag(OpenDirectoryMode.Files)) + if (Mode.HasFlag(OpenDirectoryMode.File)) { count += ParentFileSystem.Files.Length; } diff --git a/src/LibHac/Fs/PartitionFileSystemBuilder.cs b/src/LibHac/Fs/PartitionFileSystemBuilder.cs index 62fdd00b..5eed802a 100644 --- a/src/LibHac/Fs/PartitionFileSystemBuilder.cs +++ b/src/LibHac/Fs/PartitionFileSystemBuilder.cs @@ -22,7 +22,7 @@ namespace LibHac.Fs /// public PartitionFileSystemBuilder(IFileSystem input) { - IDirectory rootDir = input.OpenDirectory("/", OpenDirectoryMode.Files); + IDirectory rootDir = input.OpenDirectory("/", OpenDirectoryMode.File); foreach (DirectoryEntry file in rootDir.Read().OrderBy(x => x.FullPath, StringComparer.Ordinal)) { diff --git a/src/LibHac/Fs/RomFs/RomFsDirectory.cs b/src/LibHac/Fs/RomFs/RomFsDirectory.cs index 982ae423..3b8cb119 100644 --- a/src/LibHac/Fs/RomFs/RomFsDirectory.cs +++ b/src/LibHac/Fs/RomFs/RomFsDirectory.cs @@ -25,7 +25,7 @@ namespace LibHac.Fs.RomFs FindPosition position = InitialPosition; HierarchicalRomFileTable tab = ParentFileSystem.FileTable; - if (Mode.HasFlag(OpenDirectoryMode.Directories)) + if (Mode.HasFlag(OpenDirectoryMode.Directory)) { while (tab.FindNextDirectory(ref position, out string name)) { @@ -33,7 +33,7 @@ namespace LibHac.Fs.RomFs } } - if (Mode.HasFlag(OpenDirectoryMode.Files)) + if (Mode.HasFlag(OpenDirectoryMode.File)) { while (tab.FindNextFile(ref position, out RomFileInfo info, out string name)) { @@ -49,7 +49,7 @@ namespace LibHac.Fs.RomFs FindPosition position = InitialPosition; HierarchicalRomFileTable tab = ParentFileSystem.FileTable; - if (Mode.HasFlag(OpenDirectoryMode.Directories)) + if (Mode.HasFlag(OpenDirectoryMode.Directory)) { while (tab.FindNextDirectory(ref position, out string _)) { @@ -57,7 +57,7 @@ namespace LibHac.Fs.RomFs } } - if (Mode.HasFlag(OpenDirectoryMode.Files)) + if (Mode.HasFlag(OpenDirectoryMode.File)) { while (tab.FindNextFile(ref position, out RomFileInfo _, out string _)) { diff --git a/src/LibHac/Fs/Save/SaveDataDirectory.cs b/src/LibHac/Fs/Save/SaveDataDirectory.cs index 84a26b96..b2fe7fd3 100644 --- a/src/LibHac/Fs/Save/SaveDataDirectory.cs +++ b/src/LibHac/Fs/Save/SaveDataDirectory.cs @@ -25,7 +25,7 @@ namespace LibHac.Fs.Save SaveFindPosition position = InitialPosition; HierarchicalSaveFileTable tab = ParentFileSystem.FileTable; - if (Mode.HasFlag(OpenDirectoryMode.Directories)) + if (Mode.HasFlag(OpenDirectoryMode.Directory)) { while (tab.FindNextDirectory(ref position, out string name)) { @@ -33,7 +33,7 @@ namespace LibHac.Fs.Save } } - if (Mode.HasFlag(OpenDirectoryMode.Files)) + if (Mode.HasFlag(OpenDirectoryMode.File)) { while (tab.FindNextFile(ref position, out SaveFileInfo info, out string name)) { @@ -49,7 +49,7 @@ namespace LibHac.Fs.Save SaveFindPosition position = InitialPosition; HierarchicalSaveFileTable tab = ParentFileSystem.FileTable; - if (Mode.HasFlag(OpenDirectoryMode.Directories)) + if (Mode.HasFlag(OpenDirectoryMode.Directory)) { while (tab.FindNextDirectory(ref position, out string _)) { @@ -57,7 +57,7 @@ namespace LibHac.Fs.Save } } - if (Mode.HasFlag(OpenDirectoryMode.Files)) + if (Mode.HasFlag(OpenDirectoryMode.File)) { while (tab.FindNextFile(ref position, out SaveFileInfo _, out string _)) { diff --git a/src/LibHac/FsClient/FileSystemManagerUtils.cs b/src/LibHac/FsClient/FileSystemManagerUtils.cs index 5cdd0807..85a5b7fe 100644 --- a/src/LibHac/FsClient/FileSystemManagerUtils.cs +++ b/src/LibHac/FsClient/FileSystemManagerUtils.cs @@ -39,7 +39,7 @@ namespace LibHac.FsClient public static void CopyFile(this FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) { using (FileHandle sourceHandle = fs.OpenFile(sourcePath, OpenMode.Read)) - using (FileHandle destHandle = fs.OpenFile(destPath, OpenMode.Write | OpenMode.Append)) + using (FileHandle destHandle = fs.OpenFile(destPath, OpenMode.Write | OpenMode.AllowAppend)) { const int maxBufferSize = 0x10000; diff --git a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs index 526ffb4e..5f19cdc4 100644 --- a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs @@ -8,7 +8,7 @@ namespace LibHac.FsService.Creators { try { - baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directories); + baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directory); } catch (HorizonResultException ex) { diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs index 3b151c1e..0a0b8a62 100644 --- a/src/LibHac/FsService/Util.cs +++ b/src/LibHac/FsService/Util.cs @@ -32,7 +32,7 @@ namespace LibHac.FsService try { - baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directories); + baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directory); } catch (HorizonResultException ex) { diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index eb752b27..4aba3927 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -67,7 +67,7 @@ namespace hactoolnet public static void CopyFileWithProgress(FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) { using (FileHandle sourceHandle = fs.OpenFile(sourcePath, OpenMode.Read)) - using (FileHandle destHandle = fs.OpenFile(destPath, OpenMode.Write | OpenMode.Append)) + using (FileHandle destHandle = fs.OpenFile(destPath, OpenMode.Write | OpenMode.AllowAppend)) { const int maxBufferSize = 1024 * 1024; diff --git a/src/hactoolnet/Program.cs b/src/hactoolnet/Program.cs index 9f39a649..a1222357 100644 --- a/src/hactoolnet/Program.cs +++ b/src/hactoolnet/Program.cs @@ -57,7 +57,7 @@ namespace hactoolnet using (var logger = new ProgressBar()) { ctx.Logger = logger; - ctx.Horizon = new Horizon(new TimeSpanTimer()); + ctx.Horizon = new Horizon(new StopWatchTimeSpanGenerator()); if (ctx.Options.AccessLog != null) { From 6823aa7cb87acc149e9238361028b039fdc65f63 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 1 Sep 2019 17:20:50 -0500 Subject: [PATCH 09/46] Add placeholder FileSystemClient functions --- .../{Accessors => }/DirectoryHandle.cs | 3 +- .../FsClient/{Accessors => }/FileHandle.cs | 3 +- .../FsClient/FileSystemClient.Directory.cs | 25 ++++++ src/LibHac/FsClient/FileSystemClient.File.cs | 58 +++++++++++++ .../FsClient/FileSystemClient.FileSystem.cs | 83 +++++++++++++++++++ src/LibHac/FsClient/FileSystemClient.cs | 2 +- src/LibHac/FsClient/FileSystemManagerUtils.cs | 1 - src/hactoolnet/FsUtils.cs | 1 - 8 files changed, 171 insertions(+), 5 deletions(-) rename src/LibHac/FsClient/{Accessors => }/DirectoryHandle.cs (87%) rename src/LibHac/FsClient/{Accessors => }/FileHandle.cs (86%) create mode 100644 src/LibHac/FsClient/FileSystemClient.Directory.cs create mode 100644 src/LibHac/FsClient/FileSystemClient.File.cs create mode 100644 src/LibHac/FsClient/FileSystemClient.FileSystem.cs diff --git a/src/LibHac/FsClient/Accessors/DirectoryHandle.cs b/src/LibHac/FsClient/DirectoryHandle.cs similarity index 87% rename from src/LibHac/FsClient/Accessors/DirectoryHandle.cs rename to src/LibHac/FsClient/DirectoryHandle.cs index 05f8fb67..9eb8cf2f 100644 --- a/src/LibHac/FsClient/Accessors/DirectoryHandle.cs +++ b/src/LibHac/FsClient/DirectoryHandle.cs @@ -1,6 +1,7 @@ using System; +using LibHac.FsClient.Accessors; -namespace LibHac.FsClient.Accessors +namespace LibHac.FsClient { public struct DirectoryHandle : IDisposable { diff --git a/src/LibHac/FsClient/Accessors/FileHandle.cs b/src/LibHac/FsClient/FileHandle.cs similarity index 86% rename from src/LibHac/FsClient/Accessors/FileHandle.cs rename to src/LibHac/FsClient/FileHandle.cs index df7c8fa4..387efe01 100644 --- a/src/LibHac/FsClient/Accessors/FileHandle.cs +++ b/src/LibHac/FsClient/FileHandle.cs @@ -1,6 +1,7 @@ using System; +using LibHac.FsClient.Accessors; -namespace LibHac.FsClient.Accessors +namespace LibHac.FsClient { public struct FileHandle : IDisposable { diff --git a/src/LibHac/FsClient/FileSystemClient.Directory.cs b/src/LibHac/FsClient/FileSystemClient.Directory.cs new file mode 100644 index 00000000..e72d67c2 --- /dev/null +++ b/src/LibHac/FsClient/FileSystemClient.Directory.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using LibHac.Fs; + +namespace LibHac.FsClient +{ + public partial class FileSystemClient + { + public Result GetDirectoryEntryCount(out long count, DirectoryHandle handle) + { + throw new NotImplementedException(); + } + + // todo: change to not use IEnumerable + public IEnumerable ReadDirectory(DirectoryHandle handle) + { + throw new NotImplementedException(); + } + + public void CloseDirectory(DirectoryHandle handle) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsClient/FileSystemClient.File.cs b/src/LibHac/FsClient/FileSystemClient.File.cs new file mode 100644 index 00000000..b4b13a0f --- /dev/null +++ b/src/LibHac/FsClient/FileSystemClient.File.cs @@ -0,0 +1,58 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsClient +{ + public partial class FileSystemClient + { + public Result ReadFile(FileHandle handle, long offset, Span destination) + { + throw new NotImplementedException(); + } + + public Result ReadFile(FileHandle handle, long offset, Span destination, ReadOption options) + { + throw new NotImplementedException(); + } + + public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination) + { + throw new NotImplementedException(); + } + + public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination, ReadOption options) + { + throw new NotImplementedException(); + } + + public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source, WriteOption options) + { + throw new NotImplementedException(); + } + + public Result FlushFile(FileHandle handle) + { + throw new NotImplementedException(); + } + + public Result GetFileSize(out long size, FileHandle handle) + { + throw new NotImplementedException(); + } + + public Result SetFileSize(FileHandle handle, long size) + { + throw new NotImplementedException(); + } + + public OpenMode GetFileOpenMode(FileHandle handle) + { + throw new NotImplementedException(); + } + + public void CloseFile(FileHandle handle) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsClient/FileSystemClient.FileSystem.cs b/src/LibHac/FsClient/FileSystemClient.FileSystem.cs new file mode 100644 index 00000000..f3676a12 --- /dev/null +++ b/src/LibHac/FsClient/FileSystemClient.FileSystem.cs @@ -0,0 +1,83 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsClient +{ + public partial class FileSystemClient + { + public Result CreateDirectory(string path) + { + throw new NotImplementedException(); + } + + public Result CreateFile(string path, long size) + { + throw new NotImplementedException(); + } + + public Result CreateFile(string path, long size, CreateFileOptions options) + { + throw new NotImplementedException(); + } + + public Result DeleteDirectory(string path) + { + throw new NotImplementedException(); + } + + public Result DeleteDirectoryRecursively(string path) + { + throw new NotImplementedException(); + } + + public Result CleanDirectoryRecursively(string path) + { + throw new NotImplementedException(); + } + + public Result DeleteFile(string path) + { + throw new NotImplementedException(); + } + + public Result RenameDirectory(string oldPath, string newPath) + { + throw new NotImplementedException(); + } + + public Result RenameFile(string oldPath, string newPath) + { + throw new NotImplementedException(); + } + + public Result GetEntryType(out DirectoryEntryType type, string path) + { + throw new NotImplementedException(); + } + + public FileHandle OpenFile(out FileHandle handle, string path, OpenMode mode) + { + throw new NotImplementedException(); + } + + public DirectoryHandle OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) + { + throw new NotImplementedException(); + } + + public Result GetFreeSpaceSize(out long size, string path) + { + throw new NotImplementedException(); + } + + public Result GetTotalSpaceSize(out long size, string path) + { + throw new NotImplementedException(); + } + + public Result Commit(string mountName) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/LibHac/FsClient/FileSystemClient.cs b/src/LibHac/FsClient/FileSystemClient.cs index 9076769a..e5cfb5b8 100644 --- a/src/LibHac/FsClient/FileSystemClient.cs +++ b/src/LibHac/FsClient/FileSystemClient.cs @@ -2,7 +2,7 @@ namespace LibHac.FsClient { - public class FileSystemClient + public partial class FileSystemClient { private FileSystemServer FsSrv { get; } private FileSystemProxy FsProxy { get; set; } diff --git a/src/LibHac/FsClient/FileSystemManagerUtils.cs b/src/LibHac/FsClient/FileSystemManagerUtils.cs index 85a5b7fe..bce4b6e4 100644 --- a/src/LibHac/FsClient/FileSystemManagerUtils.cs +++ b/src/LibHac/FsClient/FileSystemManagerUtils.cs @@ -2,7 +2,6 @@ using System.Buffers; using System.Collections.Generic; using LibHac.Fs; -using LibHac.FsClient.Accessors; namespace LibHac.FsClient { diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index 4aba3927..0f41f501 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -3,7 +3,6 @@ using System.Buffers; using LibHac; using LibHac.Fs; using LibHac.FsClient; -using LibHac.FsClient.Accessors; namespace hactoolnet { From d073bdfa54b7051e200b27706bd98dd911b1f33a Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 1 Sep 2019 18:35:59 -0500 Subject: [PATCH 10/46] Change IFile and IStorage interfaces --- src/LibHac/Fs/FileBase.cs | 18 +++++++++++------- src/LibHac/Fs/IFile.cs | 10 +++++----- src/LibHac/Fs/IStorage.cs | 10 +++++----- src/LibHac/Fs/StorageBase.cs | 23 ++++++++++++----------- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/LibHac/Fs/FileBase.cs b/src/LibHac/Fs/FileBase.cs index d84b30d4..1beff741 100644 --- a/src/LibHac/Fs/FileBase.cs +++ b/src/LibHac/Fs/FileBase.cs @@ -8,11 +8,11 @@ namespace LibHac.Fs protected bool IsDisposed { get; private set; } internal List ToDispose { get; } = new List(); - public abstract int Read(Span destination, long offset, ReadOption options); - public abstract void Write(ReadOnlySpan source, long offset, WriteOption options); - public abstract void Flush(); - public abstract long GetSize(); - public abstract void SetSize(long size); + public abstract Result Read(out long bytesRead, long offset, Span destination, ReadOption options); + public abstract Result Write(long offset, ReadOnlySpan source, WriteOption options); + public abstract Result Flush(); + public abstract Result GetSize(out long size); + public abstract Result SetSize(long size); public OpenMode Mode { get; protected set; } @@ -24,7 +24,9 @@ namespace LibHac.Fs if (span == null) throw new ArgumentNullException(nameof(span)); if (offset < 0) ThrowHelper.ThrowResult(ResultFs.ValueOutOfRange, "Offset must be non-negative."); - long fileSize = GetSize(); + Result sizeResult = GetSize(out long fileSize); + sizeResult.ThrowIfFailure(); + int size = span.Length; if (offset > fileSize) ThrowHelper.ThrowResult(ResultFs.ValueOutOfRange, "Offset must be less than the file size."); @@ -41,7 +43,9 @@ namespace LibHac.Fs if (span == null) throw new ArgumentNullException(nameof(span)); if (offset < 0) ThrowHelper.ThrowResult(ResultFs.ValueOutOfRange, "Offset must be non-negative."); - long fileSize = GetSize(); + Result sizeResult = GetSize(out long fileSize); + sizeResult.ThrowIfFailure(); + int size = span.Length; if (offset + size > fileSize) diff --git a/src/LibHac/Fs/IFile.cs b/src/LibHac/Fs/IFile.cs index ad4136f9..08da0ddd 100644 --- a/src/LibHac/Fs/IFile.cs +++ b/src/LibHac/Fs/IFile.cs @@ -34,7 +34,7 @@ namespace LibHac.Fs /// size of the buffer if the IFile is too short to fulfill the request. /// is invalid. /// The file's does not allow reading. - int Read(Span destination, long offset, ReadOption options); + Result Read(out long bytesRead, long offset, Span destination, ReadOption options); /// /// Writes a sequence of bytes to the current . @@ -44,18 +44,18 @@ namespace LibHac.Fs /// Options for writing to the . /// is negative. /// The file's does not allow this request. - void Write(ReadOnlySpan source, long offset, WriteOption options); + Result Write(long offset, ReadOnlySpan source, WriteOption options); /// /// Causes any buffered data to be written to the underlying device. /// - void Flush(); + Result Flush(); /// /// Gets the number of bytes in the file. /// /// The length of the file in bytes. - long GetSize(); + Result GetSize(out long size); /// /// Sets the size of the file in bytes. @@ -63,6 +63,6 @@ namespace LibHac.Fs /// The desired size of the file in bytes. /// If increasing the file size, The file's /// does not allow this appending. - void SetSize(long size); + Result SetSize(long size); } } \ No newline at end of file diff --git a/src/LibHac/Fs/IStorage.cs b/src/LibHac/Fs/IStorage.cs index 7008d50c..8f0a1b47 100644 --- a/src/LibHac/Fs/IStorage.cs +++ b/src/LibHac/Fs/IStorage.cs @@ -14,7 +14,7 @@ namespace LibHac.Fs /// The number of bytes read will be equal to the length of the buffer. /// The offset in the at which to begin reading. /// Invalid offset or the IStorage contains fewer bytes than requested. - void Read(Span destination, long offset); + Result Read(long offset, Span destination); /// /// Writes a sequence of bytes to the current . @@ -23,24 +23,24 @@ namespace LibHac.Fs /// The offset in the at which to begin writing. /// Invalid offset or /// is too large to be written to the IStorage. - void Write(ReadOnlySpan source, long offset); + Result Write(long offset, ReadOnlySpan source); /// /// Causes any buffered data to be written to the underlying device. /// - void Flush(); + Result Flush(); /// /// Sets the size of the current IStorage. /// /// The desired size of the current IStorage in bytes. - void SetSize(long size); + Result SetSize(long size); /// /// The size of the. -1 will be returned if /// the cannot be represented as a sequence of contiguous bytes. /// /// The size of the in bytes. - long GetSize(); + Result GetSize(out long size); } } diff --git a/src/LibHac/Fs/StorageBase.cs b/src/LibHac/Fs/StorageBase.cs index fe42a6b3..580479b7 100644 --- a/src/LibHac/Fs/StorageBase.cs +++ b/src/LibHac/Fs/StorageBase.cs @@ -9,26 +9,26 @@ namespace LibHac.Fs protected internal List ToDispose { get; } = new List(); protected bool CanAutoExpand { get; set; } - protected abstract void ReadImpl(Span destination, long offset); - protected abstract void WriteImpl(ReadOnlySpan source, long offset); - public abstract void Flush(); - public abstract long GetSize(); + protected abstract Result ReadImpl(long offset, Span destination); + protected abstract Result WriteImpl(long offset, ReadOnlySpan source); + public abstract Result Flush(); + public abstract Result GetSize(out long size); - public void Read(Span destination, long offset) + public Result Read(long offset, Span destination) { ValidateParameters(destination, offset); - ReadImpl(destination, offset); + return ReadImpl(offset, destination); } - public void Write(ReadOnlySpan source, long offset) + public Result Write(long offset, ReadOnlySpan source) { ValidateParameters(source, offset); - WriteImpl(source, offset); + return WriteImpl(offset, source); } - public virtual void SetSize(long size) + public virtual Result SetSize(long size) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); + return ResultFs.NotImplemented.Log(); } protected virtual void Dispose(bool disposing) @@ -58,7 +58,8 @@ namespace LibHac.Fs if (_isDisposed) throw new ObjectDisposedException(null); if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative."); - long length = GetSize(); + Result sizeResult = GetSize(out long length); + sizeResult.ThrowIfFailure(); if (length != -1 && !CanAutoExpand) { From 69e77356669df0495cc2702e8deb146a58def0c7 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 3 Sep 2019 12:35:34 -0500 Subject: [PATCH 11/46] Change IFile and IStorage classes to return Result --- src/LibHac/Fs/Aes128CtrExStorage.cs | 16 ++-- src/LibHac/Fs/Aes128CtrStorage.cs | 14 +++- src/LibHac/Fs/Aes128XtsStorage.cs | 15 ++-- src/LibHac/Fs/AesXtsDirectory.cs | 11 ++- src/LibHac/Fs/AesXtsFile.cs | 38 ++++++---- src/LibHac/Fs/AesXtsFileHeader.cs | 4 +- src/LibHac/Fs/AesXtsFileSystem.cs | 4 +- src/LibHac/Fs/CachedStorage.cs | 38 +++++++--- src/LibHac/Fs/ConcatenationFile.cs | 73 +++++++++++++------ src/LibHac/Fs/ConcatenationStorage.cs | 37 +++++++--- src/LibHac/Fs/ConcatenationStorageBuilder.cs | 4 +- src/LibHac/Fs/Delta.cs | 8 +- src/LibHac/Fs/DirectorySaveDataFile.cs | 20 ++--- src/LibHac/Fs/FileReader.cs | 14 ++-- src/LibHac/Fs/FileStorage.cs | 23 +++--- src/LibHac/Fs/FileSystemExtensions.cs | 22 ++++-- ...ierarchicalIntegrityVerificationStorage.cs | 29 +++++--- src/LibHac/Fs/IFile.cs | 20 +++-- src/LibHac/Fs/IndirectStorage.cs | 33 ++++++--- src/LibHac/Fs/IntegrityVerificationStorage.cs | 51 +++++++------ src/LibHac/Fs/LocalFile.cs | 27 ++++--- src/LibHac/Fs/LocalStorage.cs | 17 +++-- src/LibHac/Fs/MemoryStorage.cs | 22 ++++-- src/LibHac/Fs/NcaUtils/Nca.cs | 8 +- src/LibHac/Fs/NcaUtils/NcaExtensions.cs | 4 +- src/LibHac/Fs/NcaUtils/NcaHeader.cs | 4 +- src/LibHac/Fs/NullFile.cs | 24 ++++-- src/LibHac/Fs/NullStorage.cs | 15 +++- src/LibHac/Fs/NxFileStream.cs | 16 ++-- src/LibHac/Fs/PartitionFile.cs | 33 ++++++--- src/LibHac/Fs/PartitionFileSystemBuilder.cs | 11 ++- src/LibHac/Fs/ReadOnlyFile.cs | 25 ++++--- src/LibHac/Fs/ResultFs.cs | 4 + src/LibHac/Fs/RomFs/RomFsBuilder.cs | 8 +- src/LibHac/Fs/RomFs/RomFsFile.cs | 28 ++++--- src/LibHac/Fs/Save/AllocationTable.cs | 6 +- src/LibHac/Fs/Save/AllocationTableStorage.cs | 34 ++++++--- src/LibHac/Fs/Save/DuplexStorage.cs | 45 +++++++++--- .../Fs/Save/HierarchicalDuplexStorage.cs | 20 +++-- src/LibHac/Fs/Save/JournalStorage.cs | 24 ++++-- src/LibHac/Fs/Save/RemapStorage.cs | 33 ++++++--- src/LibHac/Fs/Save/SaveDataFile.cs | 36 +++++---- src/LibHac/Fs/Save/SaveFsList.cs | 16 ++-- src/LibHac/Fs/SectorStorage.cs | 41 +++++++---- src/LibHac/Fs/StorageExtensions.cs | 54 +++++++++----- src/LibHac/Fs/StorageFile.cs | 30 +++++--- src/LibHac/Fs/StorageStream.cs | 11 +-- src/LibHac/Fs/StreamFile.cs | 27 ++++--- src/LibHac/Fs/StreamStorage.cs | 20 ++++- src/LibHac/Fs/SubStorage.cs | 44 +++++++---- src/LibHac/FsClient/Accessors/FileAccessor.cs | 42 +++++++---- src/LibHac/FsClient/FileSystemManager.cs | 26 ++++--- .../Creators/EmulatedBisFileSystemCreator.cs | 4 +- src/LibHac/FsService/FileSystemProxy.cs | 8 +- src/LibHac/FsService/FileSystemProxyCore.cs | 55 +++++++------- src/LibHac/Keyset.cs | 2 +- src/LibHac/Kip.cs | 8 +- src/LibHac/Kvdb/ImkvdbReader.cs | 4 +- src/LibHac/Kvdb/KeyValueDatabase.cs | 8 +- src/LibHac/Nro.cs | 4 +- src/LibHac/Nso.cs | 2 +- src/LibHac/Package1.cs | 2 +- src/LibHac/Package2.cs | 4 +- src/hactoolnet/ProcessBench.cs | 4 +- src/hactoolnet/ProcessDelta.cs | 6 +- src/hactoolnet/ProcessFsBuild.cs | 10 ++- src/hactoolnet/ProcessNca.cs | 7 +- src/hactoolnet/ProcessPfs.cs | 6 +- src/hactoolnet/ProcessRomfs.cs | 4 +- src/hactoolnet/ProcessSave.cs | 7 +- 70 files changed, 868 insertions(+), 506 deletions(-) diff --git a/src/LibHac/Fs/Aes128CtrExStorage.cs b/src/LibHac/Fs/Aes128CtrExStorage.cs index 9dbd3398..de3c327e 100644 --- a/src/LibHac/Fs/Aes128CtrExStorage.cs +++ b/src/LibHac/Fs/Aes128CtrExStorage.cs @@ -30,7 +30,7 @@ namespace LibHac.Fs SubsectionOffsets = SubsectionEntries.Select(x => x.Offset).ToList(); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { AesSubsectionEntry entry = GetSubsectionEntry(offset); @@ -45,7 +45,9 @@ namespace LibHac.Fs lock (_locker) { UpdateCounterSubsection(entry.Counter); - base.ReadImpl(destination.Slice(outPos, bytesToRead), inPos); + + Result rc = base.ReadImpl(inPos, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; } outPos += bytesToRead; @@ -57,16 +59,18 @@ namespace LibHac.Fs entry = entry.Next; } } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - throw new NotImplementedException(); + return ResultFs.UnsupportedOperationInAesCtrExStorageWrite.Log(); } - public override void Flush() + public override Result Flush() { - throw new NotImplementedException(); + return Result.Success; } private AesSubsectionEntry GetSubsectionEntry(long offset) diff --git a/src/LibHac/Fs/Aes128CtrStorage.cs b/src/LibHac/Fs/Aes128CtrStorage.cs index c92467eb..99bb5a40 100644 --- a/src/LibHac/Fs/Aes128CtrStorage.cs +++ b/src/LibHac/Fs/Aes128CtrStorage.cs @@ -58,18 +58,21 @@ namespace LibHac.Fs Counter = _decryptor.Counter; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - base.ReadImpl(destination, offset); + Result rc = base.ReadImpl(offset, destination); + if (rc.IsFailure()) return rc; lock (_locker) { UpdateCounter(_counterOffset + offset); _decryptor.TransformBlock(destination); } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { byte[] encrypted = ArrayPool.Shared.Rent(source.Length); try @@ -83,12 +86,15 @@ namespace LibHac.Fs _decryptor.TransformBlock(encryptedSpan); } - base.WriteImpl(encryptedSpan, offset); + Result rc = base.WriteImpl(offset, encryptedSpan); + if (rc.IsFailure()) return rc; } finally { ArrayPool.Shared.Return(encrypted); } + + return Result.Success; } private void UpdateCounter(long offset) diff --git a/src/LibHac/Fs/Aes128XtsStorage.cs b/src/LibHac/Fs/Aes128XtsStorage.cs index e4d99161..3187a8ce 100644 --- a/src/LibHac/Fs/Aes128XtsStorage.cs +++ b/src/LibHac/Fs/Aes128XtsStorage.cs @@ -37,20 +37,23 @@ namespace LibHac.Fs _key2 = key2.ToArray(); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { int size = destination.Length; long sectorIndex = offset / SectorSize; if (_decryptor == null) _decryptor = new Aes128XtsTransform(_key1, _key2, true); - base.ReadImpl(_tempBuffer.AsSpan(0, size), offset); + Result rc = base.ReadImpl(offset, _tempBuffer.AsSpan(0, size)); + if (rc.IsFailure()) return rc; _decryptor.TransformBlock(_tempBuffer, 0, size, (ulong)sectorIndex); _tempBuffer.AsSpan(0, size).CopyTo(destination); + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { int size = source.Length; long sectorIndex = offset / SectorSize; @@ -60,12 +63,12 @@ namespace LibHac.Fs source.CopyTo(_tempBuffer); _encryptor.TransformBlock(_tempBuffer, 0, size, (ulong)sectorIndex); - base.WriteImpl(_tempBuffer.AsSpan(0, size), offset); + return base.WriteImpl(offset, _tempBuffer.AsSpan(0, size)); } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } } } diff --git a/src/LibHac/Fs/AesXtsDirectory.cs b/src/LibHac/Fs/AesXtsDirectory.cs index e3400a65..d1b14e92 100644 --- a/src/LibHac/Fs/AesXtsDirectory.cs +++ b/src/LibHac/Fs/AesXtsDirectory.cs @@ -58,17 +58,20 @@ namespace LibHac.Fs { using (IFile file = BaseFileSystem.OpenFile(path, OpenMode.Read)) { - if (file.GetSize() < 0x50) + file.GetSize(out long fileSize).ThrowIfFailure(); + + if (fileSize < 0x50) { return -1; } + // todo: Use result codes var buffer = new byte[8]; - file.Read(buffer, 0x20); - if (BitConverter.ToUInt32(buffer, 0) != 0x3058414E) return 0; + file.Read(out long _, 0x20, buffer); + if (BitConverter.ToUInt32(buffer, 0) != 0x3058414E) return -1; - file.Read(buffer, 0x48); + file.Read(out long _, 0x48, buffer); return BitConverter.ToInt64(buffer, 0); } } diff --git a/src/LibHac/Fs/AesXtsFile.cs b/src/LibHac/Fs/AesXtsFile.cs index 32c5b922..fcaa6335 100644 --- a/src/LibHac/Fs/AesXtsFile.cs +++ b/src/LibHac/Fs/AesXtsFile.cs @@ -26,12 +26,14 @@ namespace LibHac.Fs Header = new AesXtsFileHeader(BaseFile); + baseFile.GetSize(out long fileSize).ThrowIfFailure(); + if (!Header.TryDecryptHeader(Path, KekSeed, VerificationKey)) { ThrowHelper.ThrowResult(ResultFs.AesXtsFileHeaderInvalidKeys, "NAX0 key derivation failed."); } - if (HeaderLength + Util.AlignUp(Header.Size, 0x10) > baseFile.GetSize()) + if (HeaderLength + Util.AlignUp(Header.Size, 0x10) > fileSize) { ThrowHelper.ThrowResult(ResultFs.AesXtsFileTooShort, "NAX0 key derivation failed."); } @@ -49,44 +51,52 @@ namespace LibHac.Fs return key; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + int toRead = ValidateReadParamsAndGetSize(destination, offset); - BaseStorage.Read(destination.Slice(0, toRead), offset); + Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + if (rc.IsFailure()) return rc; - return toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - BaseStorage.Write(source, offset); + Result rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return Header.Size; + size = Header.Size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { Header.SetSize(size, VerificationKey); - BaseFile.Write(Header.ToBytes(false), 0); + Result rc = BaseFile.Write(0, Header.ToBytes(false)); + if (rc.IsFailure()) return rc; - BaseStorage.SetSize(size); + return BaseStorage.SetSize(size); } } } diff --git a/src/LibHac/Fs/AesXtsFileHeader.cs b/src/LibHac/Fs/AesXtsFileHeader.cs index 68776041..6c416179 100644 --- a/src/LibHac/Fs/AesXtsFileHeader.cs +++ b/src/LibHac/Fs/AesXtsFileHeader.cs @@ -21,7 +21,9 @@ namespace LibHac.Fs public AesXtsFileHeader(IFile aesXtsFile) { - if (aesXtsFile.GetSize() < 0x80) + aesXtsFile.GetSize(out long fileSize).ThrowIfFailure(); + + if (fileSize < 0x80) { ThrowHelper.ThrowResult(ResultFs.AesXtsFileHeaderTooShort); } diff --git a/src/LibHac/Fs/AesXtsFileSystem.cs b/src/LibHac/Fs/AesXtsFileSystem.cs index facfbe5e..545c556f 100644 --- a/src/LibHac/Fs/AesXtsFileSystem.cs +++ b/src/LibHac/Fs/AesXtsFileSystem.cs @@ -54,7 +54,7 @@ namespace LibHac.Fs using (IFile baseFile = BaseFileSystem.OpenFile(path, OpenMode.Write)) { - baseFile.Write(header.ToBytes(false), 0); + baseFile.Write(0, header.ToBytes(false)).ThrowIfFailure(); } } @@ -235,7 +235,7 @@ namespace LibHac.Fs using (IFile file = BaseFileSystem.OpenFile(filePath, OpenMode.ReadWrite)) { - file.Write(header.ToBytes(false), 0, WriteOption.Flush); + file.Write(0, header.ToBytes(false), WriteOption.Flush).ThrowIfFailure(); } } } diff --git a/src/LibHac/Fs/CachedStorage.cs b/src/LibHac/Fs/CachedStorage.cs index a6e874f3..964a4989 100644 --- a/src/LibHac/Fs/CachedStorage.cs +++ b/src/LibHac/Fs/CachedStorage.cs @@ -16,7 +16,7 @@ namespace LibHac.Fs { BaseStorage = baseStorage; BlockSize = blockSize; - _length = BaseStorage.GetSize(); + BaseStorage.GetSize(out _length).ThrowIfFailure(); if (!leaveOpen) ToDispose.Add(BaseStorage); @@ -30,7 +30,7 @@ namespace LibHac.Fs public CachedStorage(SectorStorage baseStorage, int cacheSize, bool leaveOpen) : this(baseStorage, baseStorage.SectorSize, cacheSize, leaveOpen) { } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { long remaining = destination.Length; long inOffset = offset; @@ -53,9 +53,11 @@ namespace LibHac.Fs remaining -= bytesToRead; } } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long remaining = source.Length; long inOffset = offset; @@ -80,9 +82,11 @@ namespace LibHac.Fs remaining -= bytesToWrite; } } + + return Result.Success; } - public override void Flush() + public override Result Flush() { lock (Blocks) { @@ -92,16 +96,26 @@ namespace LibHac.Fs } } - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - BaseStorage.SetSize(size); + size = _length; + return Result.Success; + } - _length = BaseStorage.GetSize(); + public override Result SetSize(long size) + { + Result rc = BaseStorage.SetSize(size); + if (rc.IsFailure()) return rc; + + rc = BaseStorage.GetSize(out long newSize); + if (rc.IsFailure()) return rc; + + _length = newSize; + + return Result.Success; } private CacheBlock GetBlock(long blockIndex) @@ -147,7 +161,7 @@ namespace LibHac.Fs length = (int)Math.Min(_length - offset, length); } - BaseStorage.Read(block.Buffer.AsSpan(0, length), offset); + BaseStorage.Read(offset, block.Buffer.AsSpan(0, length)).ThrowIfFailure(); block.Length = length; block.Index = index; block.Dirty = false; @@ -158,7 +172,7 @@ namespace LibHac.Fs if (!block.Dirty) return; long offset = block.Index * BlockSize; - BaseStorage.Write(block.Buffer.AsSpan(0, block.Length), offset); + BaseStorage.Write(offset, block.Buffer.AsSpan(0, block.Length)).ThrowIfFailure(); block.Dirty = false; } diff --git a/src/LibHac/Fs/ConcatenationFile.cs b/src/LibHac/Fs/ConcatenationFile.cs index ad738465..b50c7594 100644 --- a/src/LibHac/Fs/ConcatenationFile.cs +++ b/src/LibHac/Fs/ConcatenationFile.cs @@ -22,7 +22,9 @@ namespace LibHac.Fs for (int i = 0; i < Sources.Count - 1; i++) { - if (Sources[i].GetSize() != SubFileSize) + Sources[i].GetSize(out long actualSubFileSize).ThrowIfFailure(); + + if (actualSubFileSize != SubFileSize) { throw new ArgumentException($"Source file must have size {subFileSize}"); } @@ -31,33 +33,41 @@ namespace LibHac.Fs ToDispose.AddRange(Sources); } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + long inPos = offset; int outPos = 0; int remaining = ValidateReadParamsAndGetSize(destination, offset); + GetSize(out long fileSize).ThrowIfFailure(); + while (remaining > 0) { int fileIndex = GetSubFileIndexFromOffset(offset); IFile file = Sources[fileIndex]; long fileOffset = offset - fileIndex * SubFileSize; - long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, GetSize()); + long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); int bytesToRead = (int)Math.Min(fileEndOffset - inPos, remaining); - int bytesRead = file.Read(destination.Slice(outPos, bytesToRead), fileOffset, options); - outPos += bytesRead; - inPos += bytesRead; - remaining -= bytesRead; + Result rc = file.Read(out long subFileBytesRead, fileOffset, destination.Slice(outPos, bytesToRead), options); + if (rc.IsFailure()) return rc; + + outPos += (int)subFileBytesRead; + inPos += subFileBytesRead; + remaining -= (int)subFileBytesRead; if (bytesRead < bytesToRead) break; } - return outPos; + bytesRead = outPos; + + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); @@ -65,15 +75,19 @@ namespace LibHac.Fs long outPos = offset; int remaining = source.Length; + GetSize(out long fileSize).ThrowIfFailure(); + while (remaining > 0) { int fileIndex = GetSubFileIndexFromOffset(outPos); IFile file = Sources[fileIndex]; long fileOffset = outPos - fileIndex * SubFileSize; - long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, GetSize()); + long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); int bytesToWrite = (int)Math.Min(fileEndOffset - outPos, remaining); - file.Write(source.Slice(inPos, bytesToWrite), fileOffset, options); + + Result rc = file.Write(fileOffset, source.Slice(inPos, bytesToWrite), options); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; @@ -82,35 +96,43 @@ namespace LibHac.Fs if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { foreach (IFile file in Sources) { - file.Flush(); + Result rc = file.Flush(); + if (rc.IsFailure()) return rc; } + + return Result.Success; } - public override long GetSize() + public override Result GetSize(out long size) { - long size = 0; + size = default; foreach (IFile file in Sources) { - size += file.GetSize(); + Result rc = file.GetSize(out long subFileSize); + if (rc.IsFailure()) return rc; + + size += subFileSize; } - return size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { - long currentSize = GetSize(); + GetSize(out long currentSize).ThrowIfFailure(); - if (currentSize == size) return; + if (currentSize == size) return Result.Success; int currentSubFileCount = QuerySubFileCount(currentSize, SubFileSize); int newSubFileCount = QuerySubFileCount(size, SubFileSize); @@ -120,7 +142,8 @@ namespace LibHac.Fs IFile currentLastSubFile = Sources[currentSubFileCount - 1]; long newSubFileSize = QuerySubFileSize(currentSubFileCount - 1, size, SubFileSize); - currentLastSubFile.SetSize(newSubFileSize); + Result rc = currentLastSubFile.SetSize(newSubFileSize); + if (rc.IsFailure()) return rc; for (int i = currentSubFileCount; i < newSubFileCount; i++) { @@ -143,8 +166,12 @@ namespace LibHac.Fs } long newLastFileSize = QuerySubFileSize(newSubFileCount - 1, size, SubFileSize); - Sources[newSubFileCount - 1].SetSize(newLastFileSize); + + Result rc = Sources[newSubFileCount - 1].SetSize(newLastFileSize); + if (rc.IsFailure()) return rc; } + + return Result.Success; } private int GetSubFileIndexFromOffset(long offset) diff --git a/src/LibHac/Fs/ConcatenationStorage.cs b/src/LibHac/Fs/ConcatenationStorage.cs index a6a6978a..af907d2f 100644 --- a/src/LibHac/Fs/ConcatenationStorage.cs +++ b/src/LibHac/Fs/ConcatenationStorage.cs @@ -16,15 +16,17 @@ namespace LibHac.Fs long length = 0; for (int i = 0; i < sources.Count; i++) { - if (sources[i].GetSize() < 0) throw new ArgumentException("Sources must have an explicit length."); - Sources[i] = new ConcatSource(sources[i], length, sources[i].GetSize()); - length += sources[i].GetSize(); + sources[i].GetSize(out long sourceSize).ThrowIfFailure(); + + if (sourceSize < 0) throw new ArgumentException("Sources must have an explicit length."); + Sources[i] = new ConcatSource(sources[i], length, sourceSize); + length += sourceSize; } _length = length; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { long inPos = offset; int outPos = 0; @@ -38,16 +40,20 @@ namespace LibHac.Fs long entryRemain = entry.StartOffset + entry.Size - inPos; int bytesToRead = (int)Math.Min(entryRemain, remaining); - entry.Storage.Read(destination.Slice(outPos, bytesToRead), entryPos); + + Result rc = entry.Storage.Read(entryPos, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; remaining -= bytesToRead; sourceIndex++; } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long inPos = offset; int outPos = 0; @@ -61,24 +67,35 @@ namespace LibHac.Fs long entryRemain = entry.StartOffset + entry.Size - inPos; int bytesToWrite = (int)Math.Min(entryRemain, remaining); - entry.Storage.Write(source.Slice(outPos, bytesToWrite), entryPos); + + Result rc = entry.Storage.Write(entryPos, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; remaining -= bytesToWrite; sourceIndex++; } + + return Result.Success; } - public override void Flush() + public override Result Flush() { foreach (ConcatSource source in Sources) { - source.Storage.Flush(); + Result rc = source.Storage.Flush(); + if (rc.IsFailure()) return rc; } + + return Result.Success; } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } private int FindSource(long offset) { diff --git a/src/LibHac/Fs/ConcatenationStorageBuilder.cs b/src/LibHac/Fs/ConcatenationStorageBuilder.cs index 3ea5f670..86749565 100644 --- a/src/LibHac/Fs/ConcatenationStorageBuilder.cs +++ b/src/LibHac/Fs/ConcatenationStorageBuilder.cs @@ -41,8 +41,10 @@ namespace LibHac.Fs sources.Add(new NullStorage(paddingNeeded)); } + segment.Storage.GetSize(out long segmentSize).ThrowIfFailure(); + sources.Add(segment.Storage); - offset = segment.Offset + segment.Storage.GetSize(); + offset = segment.Offset + segmentSize; } return new ConcatenationStorage(sources, true); diff --git a/src/LibHac/Fs/Delta.cs b/src/LibHac/Fs/Delta.cs index 26fc43d9..3a70cdd7 100644 --- a/src/LibHac/Fs/Delta.cs +++ b/src/LibHac/Fs/Delta.cs @@ -20,15 +20,16 @@ namespace LibHac.Fs public Delta(IStorage deltaStorage) { DeltaStorage = deltaStorage; + deltaStorage.GetSize(out long deltaSize).ThrowIfFailure(); - if (DeltaStorage.GetSize() < 0x40) throw new InvalidDataException("Delta file is too small."); + if (deltaSize < 0x40) throw new InvalidDataException("Delta file is too small."); Header = new DeltaHeader(deltaStorage.AsFile(OpenMode.Read)); if (Header.Magic != Ndv0Magic) throw new InvalidDataException("NDV0 magic value is missing."); long fragmentSize = Header.HeaderSize + Header.BodySize; - if (DeltaStorage.GetSize() < fragmentSize) + if (deltaSize < fragmentSize) { throw new InvalidDataException($"Delta file is smaller than the header indicates. (0x{fragmentSize} bytes)"); } @@ -39,8 +40,9 @@ namespace LibHac.Fs public void SetBaseStorage(IStorage baseStorage) { OriginalStorage = baseStorage; + baseStorage.GetSize(out long storageSize).ThrowIfFailure(); - if (OriginalStorage.GetSize() != Header.OriginalSize) + if (storageSize != Header.OriginalSize) { throw new InvalidDataException($"Original file size does not match the size in the delta header. (0x{Header.OriginalSize} bytes)"); } diff --git a/src/LibHac/Fs/DirectorySaveDataFile.cs b/src/LibHac/Fs/DirectorySaveDataFile.cs index 7bda0da9..2c68ad92 100644 --- a/src/LibHac/Fs/DirectorySaveDataFile.cs +++ b/src/LibHac/Fs/DirectorySaveDataFile.cs @@ -16,29 +16,29 @@ namespace LibHac.Fs ToDispose.Add(BaseFile); } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { - return BaseFile.Read(destination, offset, options); + return BaseFile.Read(out bytesRead, offset, destination, options); } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { - BaseFile.Write(source, offset, options); + return BaseFile.Write(offset, source, options); } - public override void Flush() + public override Result Flush() { - BaseFile.Flush(); + return BaseFile.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return BaseFile.GetSize(); + return BaseFile.GetSize(out size); } - public override void SetSize(long size) + public override Result SetSize(long size) { - BaseFile.SetSize(size); + return BaseFile.SetSize(size); } protected override void Dispose(bool disposing) diff --git a/src/LibHac/Fs/FileReader.cs b/src/LibHac/Fs/FileReader.cs index 5a7779f1..25f54ea9 100644 --- a/src/LibHac/Fs/FileReader.cs +++ b/src/LibHac/Fs/FileReader.cs @@ -31,7 +31,7 @@ namespace LibHac.Fs { Debug.Assert(count <= BufferSize); - _file.Read(_buffer.AsSpan(0, count), _start + offset); + _file.Read(out long _, _start + offset, _buffer.AsSpan(0, count)).ThrowIfFailure(); if (updatePosition) Position = offset + count; } @@ -101,7 +101,7 @@ namespace LibHac.Fs public long ReadInt64(long offset, bool updatePosition) { FillBuffer(offset, sizeof(long), updatePosition); - + return MemoryMarshal.Read(_buffer); } @@ -121,16 +121,16 @@ namespace LibHac.Fs public byte[] ReadBytes(long offset, int length, bool updatePosition) { - var result = new byte[length]; - _file.Read(result, offset); + var bytes = new byte[length]; + _file.Read(out long _, offset, bytes).ThrowIfFailure(); if (updatePosition) Position = offset + length; - return result; + return bytes; } public void ReadBytes(Span destination, long offset, bool updatePosition) { - _file.Read(destination, offset); + _file.Read(out long _, offset, destination).ThrowIfFailure(); if (updatePosition) Position = offset + destination.Length; } @@ -138,7 +138,7 @@ namespace LibHac.Fs public string ReadAscii(long offset, int length, bool updatePosition) { var bytes = new byte[length]; - _file.Read(bytes, offset); + _file.Read(out long _, offset, bytes).ThrowIfFailure(); if (updatePosition) Position = offset + length; return Encoding.ASCII.GetString(bytes); diff --git a/src/LibHac/Fs/FileStorage.cs b/src/LibHac/Fs/FileStorage.cs index 80c8e6bc..1b0ae864 100644 --- a/src/LibHac/Fs/FileStorage.cs +++ b/src/LibHac/Fs/FileStorage.cs @@ -11,26 +11,29 @@ namespace LibHac.Fs BaseFile = baseFile; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - BaseFile.Read(destination, offset); + return BaseFile.Read(out long _, offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - BaseFile.Write(source, offset); + return BaseFile.Write(offset, source); } - public override void Flush() + public override Result Flush() { - BaseFile.Flush(); + return BaseFile.Flush(); } - public override long GetSize() => BaseFile.GetSize(); - - public override void SetSize(long size) + public override Result GetSize(out long size) { - BaseFile.SetSize(size); + return BaseFile.GetSize(out size); + } + + public override Result SetSize(long size) + { + return BaseFile.SetSize(size); } } } diff --git a/src/LibHac/Fs/FileSystemExtensions.cs b/src/LibHac/Fs/FileSystemExtensions.cs index 8669d230..22643be6 100644 --- a/src/LibHac/Fs/FileSystemExtensions.cs +++ b/src/LibHac/Fs/FileSystemExtensions.cs @@ -103,17 +103,23 @@ namespace LibHac.Fs public static void CopyTo(this IFile file, IFile dest, IProgressReport logger = null) { const int bufferSize = 0x8000; - logger?.SetTotal(file.GetSize()); + + file.GetSize(out long fileSize).ThrowIfFailure(); + + logger?.SetTotal(fileSize); byte[] buffer = ArrayPool.Shared.Rent(bufferSize); try { long inOffset = 0; - int bytesRead; - while ((bytesRead = file.Read(buffer, inOffset)) != 0) + // todo: use result for loop condition + while (true) { - dest.Write(buffer.AsSpan(0, bytesRead), inOffset); + file.Read(out long bytesRead, inOffset, buffer).ThrowIfFailure(); + if (bytesRead == 0) break; + + dest.Write(inOffset, buffer.AsSpan(0, (int)bytesRead)).ThrowIfFailure(); inOffset += bytesRead; logger?.ReportAdd(bytesRead); } @@ -190,14 +196,14 @@ namespace LibHac.Fs } } - public static int Read(this IFile file, Span destination, long offset) + public static Result Read(this IFile file, out long bytesRead, long offset, Span destination) { - return file.Read(destination, offset, ReadOption.None); + return file.Read(out bytesRead, offset, destination, ReadOption.None); } - public static void Write(this IFile file, ReadOnlySpan source, long offset) + public static Result Write(this IFile file, long offset, ReadOnlySpan source) { - file.Write(source, offset, WriteOption.None); + return file.Write(offset, source, WriteOption.None); } public static bool DirectoryExists(this IFileSystem fs, string path) diff --git a/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs b/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs index a81f438a..92001edf 100644 --- a/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs +++ b/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs @@ -33,8 +33,9 @@ namespace LibHac.Fs for (int i = 1; i < Levels.Length; i++) { var levelData = new IntegrityVerificationStorage(levelInfo[i], Levels[i - 1], integrityCheckLevel, leaveOpen); + levelData.GetSize(out long levelSize).ThrowIfFailure(); - int cacheCount = Math.Min((int)Util.DivideByRoundUp(levelData.GetSize(), levelInfo[i].BlockSize), 4); + int cacheCount = Math.Min((int)Util.DivideByRoundUp(levelSize, levelInfo[i].BlockSize), 4); Levels[i] = new CachedStorage(levelData, cacheCount, leaveOpen); LevelValidities[i - 1] = levelData.BlockValidities; @@ -42,7 +43,7 @@ namespace LibHac.Fs } DataLevel = Levels[Levels.Length - 1]; - _length = DataLevel.GetSize(); + DataLevel.GetSize(out _length).ThrowIfFailure(); if (!leaveOpen) ToDispose.Add(DataLevel); } @@ -92,22 +93,26 @@ namespace LibHac.Fs return initInfo; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - DataLevel.Read(destination, offset); + return DataLevel.Read(offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - DataLevel.Write(source, offset); + return DataLevel.Write(offset, source); } - public override void Flush() + public override Result Flush() { - DataLevel.Flush(); + return DataLevel.Flush(); } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } /// /// Checks the hashes of any unchecked blocks and returns the of the data. @@ -132,8 +137,10 @@ namespace LibHac.Fs { if (validities[i] == Validity.Unchecked) { - int toRead = (int)Math.Min(storage.GetSize() - blockSize * i, buffer.Length); - storage.Read(buffer.AsSpan(0, toRead), blockSize * i, IntegrityCheckLevel.IgnoreOnInvalid); + storage.GetSize(out long storageSize).ThrowIfFailure(); + int toRead = (int)Math.Min(storageSize - blockSize * i, buffer.Length); + + storage.Read(blockSize * i, buffer.AsSpan(0, toRead), IntegrityCheckLevel.IgnoreOnInvalid); } if (validities[i] == Validity.Invalid) diff --git a/src/LibHac/Fs/IFile.cs b/src/LibHac/Fs/IFile.cs index 08da0ddd..da2a5644 100644 --- a/src/LibHac/Fs/IFile.cs +++ b/src/LibHac/Fs/IFile.cs @@ -26,24 +26,22 @@ namespace LibHac.Fs /// /// Reads a sequence of bytes from the current . /// + /// If the operation returns successfully, The total number of bytes read into + /// the buffer. This can be less than the size of the buffer if the IFile is too short to fulfill the request. + /// The offset in the at which to begin reading. /// The buffer where the read bytes will be stored. /// The number of bytes read will be no larger than the length of the buffer. - /// The offset in the at which to begin reading. /// Options for reading from the . - /// The total number of bytes read into the buffer. This can be less than the - /// size of the buffer if the IFile is too short to fulfill the request. - /// is invalid. - /// The file's does not allow reading. + /// The of the requested operation. Result Read(out long bytesRead, long offset, Span destination, ReadOption options); /// /// Writes a sequence of bytes to the current . /// - /// The buffer containing the bytes to be written. /// The offset in the at which to begin writing. + /// The buffer containing the bytes to be written. /// Options for writing to the . - /// is negative. - /// The file's does not allow this request. + /// The of the requested operation. Result Write(long offset, ReadOnlySpan source, WriteOption options); /// @@ -54,15 +52,15 @@ namespace LibHac.Fs /// /// Gets the number of bytes in the file. /// - /// The length of the file in bytes. + /// If the operation returns successfully, the length of the file in bytes. + /// The of the requested operation. Result GetSize(out long size); /// /// Sets the size of the file in bytes. /// /// The desired size of the file in bytes. - /// If increasing the file size, The file's - /// does not allow this appending. + /// The of the requested operation. Result SetSize(long size); } } \ No newline at end of file diff --git a/src/LibHac/Fs/IndirectStorage.cs b/src/LibHac/Fs/IndirectStorage.cs index 443e9c1a..f49336b0 100644 --- a/src/LibHac/Fs/IndirectStorage.cs +++ b/src/LibHac/Fs/IndirectStorage.cs @@ -27,13 +27,13 @@ namespace LibHac.Fs _length = BucketTree.BucketOffsets.OffsetEnd; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { RelocationEntry entry = GetRelocationEntry(offset); if (entry.SourceIndex > Sources.Count) { - ThrowHelper.ThrowResult(ResultFs.InvalidIndirectStorageSource); + return ResultFs.InvalidIndirectStorageSource.Log(); } long inPos = offset; @@ -45,7 +45,9 @@ namespace LibHac.Fs long entryPos = inPos - entry.Offset; int bytesToRead = (int)Math.Min(entry.OffsetEnd - inPos, remaining); - Sources[entry.SourceIndex].Read(destination.Slice(outPos, bytesToRead), entry.SourceOffset + entryPos); + + Result rc = Sources[entry.SourceIndex].Read(entry.SourceOffset + entryPos, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; @@ -56,20 +58,29 @@ namespace LibHac.Fs entry = entry.Next; } } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInIndirectStorageWrite); + return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log(); } - public override void Flush() { } - - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result Flush() { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInIndirectStorageSetSize); + return Result.Success; + } + + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } + + public override Result SetSize(long size) + { + return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log(); } private RelocationEntry GetRelocationEntry(long offset) diff --git a/src/LibHac/Fs/IntegrityVerificationStorage.cs b/src/LibHac/Fs/IntegrityVerificationStorage.cs index e03db3df..4adbab58 100644 --- a/src/LibHac/Fs/IntegrityVerificationStorage.cs +++ b/src/LibHac/Fs/IntegrityVerificationStorage.cs @@ -32,7 +32,7 @@ namespace LibHac.Fs BlockValidities = new Validity[SectorCount]; } - private void ReadImpl(Span destination, long offset, IntegrityCheckLevel integrityCheckLevel) + private Result ReadImpl(long offset, Span destination, IntegrityCheckLevel integrityCheckLevel) { int count = destination.Length; @@ -52,13 +52,13 @@ namespace LibHac.Fs if (Type != IntegrityStorageType.Save && !needsHashCheck) { - BaseStorage.Read(destination, offset); - return; + BaseStorage.Read(offset, destination); + return Result.Success; } Span hashBuffer = stackalloc byte[DigestSize]; long hashPos = blockIndex * DigestSize; - HashStorage.Read(hashBuffer, hashPos); + HashStorage.Read(hashPos, hashBuffer); if (Type == IntegrityStorageType.Save) { @@ -66,23 +66,23 @@ namespace LibHac.Fs { destination.Clear(); BlockValidities[blockIndex] = Validity.Valid; - return; + return Result.Success; } if (!needsHashCheck) { - BaseStorage.Read(destination, offset); - return; + BaseStorage.Read(offset, destination); + return Result.Success; } } byte[] dataBuffer = ArrayPool.Shared.Rent(SectorSize); try { - BaseStorage.Read(destination, offset); + BaseStorage.Read(offset, destination); destination.CopyTo(dataBuffer); - if (BlockValidities[blockIndex] != Validity.Unchecked) return; + if (BlockValidities[blockIndex] != Validity.Unchecked) return Result.Success; int bytesToHash = SectorSize; @@ -112,25 +112,30 @@ namespace LibHac.Fs { ArrayPool.Shared.Return(dataBuffer); } + + return Result.Success; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - ReadImpl(destination, offset, IntegrityCheckLevel); + return ReadImpl(offset, destination, IntegrityCheckLevel); } - public void Read(Span destination, long offset, IntegrityCheckLevel integrityCheckLevel) + public Result Read(long offset, Span destination, IntegrityCheckLevel integrityCheckLevel) { ValidateParameters(destination, offset); - ReadImpl(destination, offset, integrityCheckLevel); + return ReadImpl(offset, destination, integrityCheckLevel); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long blockIndex = offset / SectorSize; long hashPos = blockIndex * DigestSize; - int toWrite = (int)Math.Min(source.Length, GetSize() - offset); + Result rc = GetSize(out long storageSize); + if (rc.IsFailure()) return rc; + + int toWrite = (int)Math.Min(source.Length, storageSize - offset); byte[] dataBuffer = ArrayPool.Shared.Rent(SectorSize); try @@ -143,15 +148,17 @@ namespace LibHac.Fs Array.Clear(hash, 0, DigestSize); } - BaseStorage.Write(source, offset); + BaseStorage.Write(offset, source); - HashStorage.Write(hash, hashPos); + HashStorage.Write(hashPos, hash); BlockValidities[blockIndex] = Validity.Unchecked; } finally { ArrayPool.Shared.Return(dataBuffer); } + + return Result.Success; } private byte[] DoHash(byte[] buffer, int offset, int count) @@ -180,10 +187,12 @@ namespace LibHac.Fs } } - public override void Flush() + public override Result Flush() { - HashStorage.Flush(); - base.Flush(); + Result rc = HashStorage.Flush(); + if (rc.IsFailure()) return rc; + + return base.Flush(); } public void FsTrim() @@ -195,7 +204,7 @@ namespace LibHac.Fs for (int i = 0; i < SectorCount; i++) { long hashPos = i * DigestSize; - HashStorage.Read(digest, hashPos); + HashStorage.Read(hashPos, digest).ThrowIfFailure(); if (!Util.IsEmpty(digest)) continue; diff --git a/src/LibHac/Fs/LocalFile.cs b/src/LibHac/Fs/LocalFile.cs index 950af64f..4cb9e655 100644 --- a/src/LibHac/Fs/LocalFile.cs +++ b/src/LibHac/Fs/LocalFile.cs @@ -21,33 +21,31 @@ namespace LibHac.Fs ToDispose.Add(Stream); } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { int toRead = ValidateReadParamsAndGetSize(destination, offset); - File.Read(destination.Slice(0, toRead), offset, options); - - return toRead; + return File.Read(out bytesRead, offset, destination.Slice(0, toRead), options); } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - - File.Write(source, offset, options); + + return File.Write(offset, source, options); } - public override void Flush() + public override Result Flush() { - File.Flush(); + return File.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return File.GetSize(); + return File.GetSize(out size); } - public override void SetSize(long size) + public override Result SetSize(long size) { try { @@ -55,9 +53,10 @@ namespace LibHac.Fs } catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) { - ThrowHelper.ThrowResult(ResultFs.InsufficientFreeSpace, ex); - throw; + return ResultFs.InsufficientFreeSpace.Log(); } + + return Result.Success; } private static FileAccess GetFileAccess(OpenMode mode) diff --git a/src/LibHac/Fs/LocalStorage.cs b/src/LibHac/Fs/LocalStorage.cs index 6d990699..ea5b6e20 100644 --- a/src/LibHac/Fs/LocalStorage.cs +++ b/src/LibHac/Fs/LocalStorage.cs @@ -21,21 +21,24 @@ namespace LibHac.Fs ToDispose.Add(Stream); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - Storage.Read(destination, offset); + return Storage.Read(offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - Storage.Write(source, offset); + return Storage.Write(offset, source); } - public override void Flush() + public override Result Flush() { - Storage.Flush(); + return Storage.Flush(); } - public override long GetSize() => Storage.GetSize(); + public override Result GetSize(out long size) + { + return Storage.GetSize(out size); + } } } diff --git a/src/LibHac/Fs/MemoryStorage.cs b/src/LibHac/Fs/MemoryStorage.cs index fb88a181..23c025ff 100644 --- a/src/LibHac/Fs/MemoryStorage.cs +++ b/src/LibHac/Fs/MemoryStorage.cs @@ -38,12 +38,14 @@ namespace LibHac.Fs _isExpandable = false; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { _buffer.AsSpan((int)(_start + offset), destination.Length).CopyTo(destination); + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long requiredCapacity = _start + offset + source.Length; @@ -54,6 +56,8 @@ namespace LibHac.Fs } source.CopyTo(_buffer.AsSpan((int)(_start + offset), source.Length)); + + return Result.Success; } public byte[] ToArray() @@ -92,13 +96,17 @@ namespace LibHac.Fs } } - public override void Flush() { } + public override Result Flush() => Result.Success; - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInMemoryStorageSetSize); + size = _length; + return Result.Success; + } + + public override Result SetSize(long size) + { + return ResultFs.UnsupportedOperationInMemoryStorageSetSize.Log(); } } } diff --git a/src/LibHac/Fs/NcaUtils/Nca.cs b/src/LibHac/Fs/NcaUtils/Nca.cs index 7296aa5c..ed892d26 100644 --- a/src/LibHac/Fs/NcaUtils/Nca.cs +++ b/src/LibHac/Fs/NcaUtils/Nca.cs @@ -117,10 +117,12 @@ namespace LibHac.Fs.NcaUtils long offset = Header.GetSectionStartOffset(index); long size = Header.GetSectionSize(index); - if (!Util.IsSubRange(offset, size, BaseStorage.GetSize())) + BaseStorage.GetSize(out long baseSize).ThrowIfFailure(); + + if (!Util.IsSubRange(offset, size, baseSize)) { throw new InvalidDataException( - $"Section offset (0x{offset:x}) and length (0x{size:x}) fall outside the total NCA length (0x{BaseStorage.GetSize():x})."); + $"Section offset (0x{offset:x}) and length (0x{size:x}) fall outside the total NCA length (0x{baseSize:x})."); } return BaseStorage.Slice(offset, size); @@ -492,7 +494,7 @@ namespace LibHac.Fs.NcaUtils private int ReadHeaderVersion(IStorage header) { Span buf = stackalloc byte[1]; - header.Read(buf, 0x203); + header.Read(0x203, buf).Log(); return buf[0] - '0'; } diff --git a/src/LibHac/Fs/NcaUtils/NcaExtensions.cs b/src/LibHac/Fs/NcaUtils/NcaExtensions.cs index 42f8bb0e..72cbc384 100644 --- a/src/LibHac/Fs/NcaUtils/NcaExtensions.cs +++ b/src/LibHac/Fs/NcaUtils/NcaExtensions.cs @@ -95,7 +95,7 @@ namespace LibHac.Fs.NcaUtils IStorage storage = nca.OpenRawStorage(index); var data = new byte[size]; - storage.Read(data, offset); + storage.Read(offset, data).ThrowIfFailure(); byte[] actualHash = Crypto.ComputeSha256(data, 0, data.Length); @@ -116,7 +116,7 @@ namespace LibHac.Fs.NcaUtils IStorage decryptedStorage = nca.OpenRawStorage(index); Span buffer = stackalloc byte[sizeof(long)]; - decryptedStorage.Read(buffer, header.EncryptionTreeOffset + 8); + decryptedStorage.Read(header.EncryptionTreeOffset + 8, buffer).ThrowIfFailure(); long readDataSize = BinaryPrimitives.ReadInt64LittleEndian(buffer); if (header.EncryptionTreeOffset != readDataSize) return Validity.Invalid; diff --git a/src/LibHac/Fs/NcaUtils/NcaHeader.cs b/src/LibHac/Fs/NcaUtils/NcaHeader.cs index d15dcbf9..d4580f9a 100644 --- a/src/LibHac/Fs/NcaUtils/NcaHeader.cs +++ b/src/LibHac/Fs/NcaUtils/NcaHeader.cs @@ -17,7 +17,7 @@ namespace LibHac.Fs.NcaUtils public NcaHeader(IStorage headerStorage) { _header = new byte[HeaderSize]; - headerStorage.Read(_header.Span, 0); + headerStorage.Read(0, _header.Span); } public NcaHeader(Keyset keyset, IStorage headerStorage) @@ -188,7 +188,7 @@ namespace LibHac.Fs.NcaUtils public static byte[] DecryptHeader(Keyset keyset, IStorage storage) { var buf = new byte[HeaderSize]; - storage.Read(buf, 0); + storage.Read(0, buf); byte[] key1 = keyset.HeaderKey.AsSpan(0, 0x10).ToArray(); byte[] key2 = keyset.HeaderKey.AsSpan(0x10, 0x10).ToArray(); diff --git a/src/LibHac/Fs/NullFile.cs b/src/LibHac/Fs/NullFile.cs index 71081c69..8c396639 100644 --- a/src/LibHac/Fs/NullFile.cs +++ b/src/LibHac/Fs/NullFile.cs @@ -13,26 +13,34 @@ namespace LibHac.Fs private long Length { get; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { int toRead = ValidateReadParamsAndGetSize(destination, offset); destination.Slice(0, toRead).Clear(); - return toRead; + + bytesRead = toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { + return Result.Success; } - public override void Flush() + public override Result Flush() { + return Result.Success; } - public override long GetSize() => Length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - throw new NotSupportedException(); + size = Length; + return Result.Success; + } + + public override Result SetSize(long size) + { + return ResultFs.UnsupportedOperation.Log(); } } } diff --git a/src/LibHac/Fs/NullStorage.cs b/src/LibHac/Fs/NullStorage.cs index 83c6dbfe..5643e70b 100644 --- a/src/LibHac/Fs/NullStorage.cs +++ b/src/LibHac/Fs/NullStorage.cs @@ -12,19 +12,26 @@ namespace LibHac.Fs private long _length; - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { destination.Clear(); + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { + return Result.Success; } - public override void Flush() + public override Result Flush() { + return Result.Success; } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } } } diff --git a/src/LibHac/Fs/NxFileStream.cs b/src/LibHac/Fs/NxFileStream.cs index 5720e81e..fd2a0852 100644 --- a/src/LibHac/Fs/NxFileStream.cs +++ b/src/LibHac/Fs/NxFileStream.cs @@ -13,21 +13,21 @@ namespace LibHac.Fs { BaseFile = baseFile; LeaveOpen = leaveOpen; - _length = baseFile.GetSize(); + + baseFile.GetSize(out _length).ThrowIfFailure(); } public override int Read(byte[] buffer, int offset, int count) { - int toRead = (int)Math.Min(count, Length - Position); - BaseFile.Read(buffer.AsSpan(offset, toRead), Position); + BaseFile.Read(out long bytesRead, Position, buffer.AsSpan(offset, count)); - Position += toRead; - return toRead; + Position += bytesRead; + return (int)bytesRead; } public override void Write(byte[] buffer, int offset, int count) { - BaseFile.Write(buffer.AsSpan(offset, count), Position); + BaseFile.Write(Position, buffer.AsSpan(offset, count)); Position += count; } @@ -57,9 +57,9 @@ namespace LibHac.Fs public override void SetLength(long value) { - BaseFile.SetSize(value); + BaseFile.SetSize(value).ThrowIfFailure(); - _length = BaseFile.GetSize(); + BaseFile.GetSize(out _length).ThrowIfFailure(); } public override bool CanRead => BaseFile.Mode.HasFlag(OpenMode.Read); diff --git a/src/LibHac/Fs/PartitionFile.cs b/src/LibHac/Fs/PartitionFile.cs index 44416dd4..1802ea87 100644 --- a/src/LibHac/Fs/PartitionFile.cs +++ b/src/LibHac/Fs/PartitionFile.cs @@ -16,44 +16,53 @@ namespace LibHac.Fs Size = size; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + int toRead = ValidateReadParamsAndGetSize(destination, offset); long storageOffset = Offset + offset; - BaseStorage.Read(destination.Slice(0, toRead), storageOffset); + BaseStorage.Read(storageOffset, destination.Slice(0, toRead)); - return toRead; + bytesRead = toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - BaseStorage.Write(source, offset); + Result rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; if ((options & WriteOption.Flush) != 0) { - BaseStorage.Flush(); + return BaseStorage.Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { if ((Mode & OpenMode.Write) != 0) { - BaseStorage.Flush(); + return BaseStorage.Flush(); } + + return Result.Success; } - public override long GetSize() + public override Result GetSize(out long size) { - return Size; + size = Size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInPartitionFileSetSize); + return ResultFs.UnsupportedOperationInPartitionFileSetSize.Log(); } } } diff --git a/src/LibHac/Fs/PartitionFileSystemBuilder.cs b/src/LibHac/Fs/PartitionFileSystemBuilder.cs index 5eed802a..d997dd0f 100644 --- a/src/LibHac/Fs/PartitionFileSystemBuilder.cs +++ b/src/LibHac/Fs/PartitionFileSystemBuilder.cs @@ -32,11 +32,13 @@ namespace LibHac.Fs public void AddFile(string filename, IFile file) { + file.GetSize(out long fileSize).ThrowIfFailure(); + var entry = new Entry { Name = filename, File = file, - Length = file.GetSize(), + Length = fileSize, Offset = CurrentOffset, NameLength = Encoding.UTF8.GetByteCount(filename), HashOffset = 0, @@ -148,7 +150,12 @@ namespace LibHac.Fs if (entry.HashLength == 0) entry.HashLength = 0x200; var data = new byte[entry.HashLength]; - entry.File.Read(data, entry.HashOffset); + entry.File.Read(out long bytesRead, entry.HashOffset, data); + + if (bytesRead != entry.HashLength) + { + throw new ArgumentOutOfRangeException(); + } entry.Hash = sha.ComputeHash(data); } diff --git a/src/LibHac/Fs/ReadOnlyFile.cs b/src/LibHac/Fs/ReadOnlyFile.cs index 14064046..f98b8b24 100644 --- a/src/LibHac/Fs/ReadOnlyFile.cs +++ b/src/LibHac/Fs/ReadOnlyFile.cs @@ -11,22 +11,29 @@ namespace LibHac.Fs BaseFile = baseFile; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { - return BaseFile.Read(destination, offset, options); + return BaseFile.Read(out bytesRead, offset, destination, options); } - public override long GetSize() + public override Result GetSize(out long size) { - return BaseFile.GetSize(); + return BaseFile.GetSize(out size); } - public override void Flush() { } + public override Result Flush() + { + return Result.Success; + } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFile); + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + { + return ResultFs.UnsupportedOperationModifyReadOnlyFile.Log(); + } - public override void SetSize(long size) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFile); + public override Result SetSize(long size) + { + return ResultFs.UnsupportedOperationModifyReadOnlyFile.Log(); + } } } diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 4cc73c86..a3733289 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -87,8 +87,11 @@ public static Result InvalidOpenModeForWrite => new Result(ModuleFs, 6203); public static Result UnsupportedOperation => new Result(ModuleFs, 6300); + public static Result SubStorageNotResizable => new Result(ModuleFs, 6302); + public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6302); public static Result UnsupportedOperationInMemoryStorageSetSize => new Result(ModuleFs, 6316); public static Result UnsupportedOperationInHierarchicalIvfcStorageSetSize => new Result(ModuleFs, 6304); + public static Result UnsupportedOperationInAesCtrExStorageWrite => new Result(ModuleFs, 6310); public static Result UnsupportedOperationInIndirectStorageWrite => new Result(ModuleFs, 6324); public static Result UnsupportedOperationInIndirectStorageSetSize => new Result(ModuleFs, 6325); public static Result UnsupportedOperationInConcatFsQueryEntry => new Result(ModuleFs, 6359); @@ -108,6 +111,7 @@ public static Result AllocationTableInsufficientFreeBlocks => new Result(ModuleFs, 6707); + public static Result Result6902 => new Result(ModuleFs, 6902); public static Result MountNameNotFound => new Result(ModuleFs, 6905); } } diff --git a/src/LibHac/Fs/RomFs/RomFsBuilder.cs b/src/LibHac/Fs/RomFs/RomFsBuilder.cs index 0d745d31..8d067e6e 100644 --- a/src/LibHac/Fs/RomFs/RomFsBuilder.cs +++ b/src/LibHac/Fs/RomFs/RomFsBuilder.cs @@ -47,7 +47,7 @@ namespace LibHac.Fs.RomFs public void AddFile(string path, IFile file) { var fileInfo = new RomFileInfo(); - long fileSize = file.GetSize(); + file.GetSize(out long fileSize).ThrowIfFailure(); fileInfo.Offset = CurrentOffset; fileInfo.Length = fileSize; @@ -81,7 +81,11 @@ namespace LibHac.Fs.RomFs sources.Add(new MemoryStorage(header)); sources.AddRange(Sources); - long fileLength = sources.Sum(x => x.GetSize()); + long fileLength = sources.Sum(x => + { + x.GetSize(out long fileSize).ThrowIfFailure(); + return fileSize; + }); headerWriter.Write((long)HeaderSize); diff --git a/src/LibHac/Fs/RomFs/RomFsFile.cs b/src/LibHac/Fs/RomFs/RomFsFile.cs index 30e8a0c0..5f58a54a 100644 --- a/src/LibHac/Fs/RomFs/RomFsFile.cs +++ b/src/LibHac/Fs/RomFs/RomFsFile.cs @@ -16,33 +16,41 @@ namespace LibHac.Fs.RomFs Size = size; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + int toRead = ValidateReadParamsAndGetSize(destination, offset); long storageOffset = Offset + offset; - BaseStorage.Read(destination.Slice(0, toRead), storageOffset); - return toRead; + Result rc = BaseStorage.Read(storageOffset, destination.Slice(0, toRead)); + if (rc.IsFailure()) return rc; + + bytesRead = toRead; + + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFile); + return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } - public override void Flush() + public override Result Flush() { + return Result.Success; } - public override long GetSize() + public override Result GetSize(out long size) { - return Size; + size = Size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFile); + return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } } } diff --git a/src/LibHac/Fs/Save/AllocationTable.cs b/src/LibHac/Fs/Save/AllocationTable.cs index ad85e744..c43ec471 100644 --- a/src/LibHac/Fs/Save/AllocationTable.cs +++ b/src/LibHac/Fs/Save/AllocationTable.cs @@ -356,7 +356,7 @@ namespace LibHac.Fs.Save Span buffer = MemoryMarshal.Cast(entries.Slice(0, entriesToRead)); - BaseStorage.Read(buffer, offset); + BaseStorage.Read(offset, buffer).ThrowIfFailure(); } private AllocationTableEntry ReadEntry(int entryIndex) @@ -364,7 +364,7 @@ namespace LibHac.Fs.Save Span bytes = stackalloc byte[EntrySize]; int offset = entryIndex * EntrySize; - BaseStorage.Read(bytes, offset); + BaseStorage.Read(offset, bytes).ThrowIfFailure(); return GetEntryFromBytes(bytes); } @@ -377,7 +377,7 @@ namespace LibHac.Fs.Save ref AllocationTableEntry newEntry = ref GetEntryFromBytes(bytes); newEntry = entry; - BaseStorage.Write(bytes, offset); + BaseStorage.Write(offset, bytes).ThrowIfFailure(); } // ReSharper disable once UnusedMember.Local diff --git a/src/LibHac/Fs/Save/AllocationTableStorage.cs b/src/LibHac/Fs/Save/AllocationTableStorage.cs index d210bd10..c15102b1 100644 --- a/src/LibHac/Fs/Save/AllocationTableStorage.cs +++ b/src/LibHac/Fs/Save/AllocationTableStorage.cs @@ -22,7 +22,7 @@ namespace LibHac.Fs.Save _length = initialBlock == -1 ? 0 : table.GetListLength(initialBlock) * blockSize; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { var iterator = new AllocationTableIterator(Fat, InitialBlock); @@ -41,15 +41,18 @@ namespace LibHac.Fs.Save int remainingInSegment = iterator.CurrentSegmentSize * BlockSize - segmentPos; int bytesToRead = Math.Min(remaining, remainingInSegment); - BaseStorage.Read(destination.Slice(outPos, bytesToRead), physicalOffset); + Result rc = BaseStorage.Read(physicalOffset, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; remaining -= bytesToRead; } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { var iterator = new AllocationTableIterator(Fat, InitialBlock); @@ -68,27 +71,34 @@ namespace LibHac.Fs.Save int remainingInSegment = iterator.CurrentSegmentSize * BlockSize - segmentPos; int bytesToWrite = Math.Min(remaining, remainingInSegment); - BaseStorage.Write(source.Slice(outPos, bytesToWrite), physicalOffset); + Result rc = BaseStorage.Write(physicalOffset, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; remaining -= bytesToWrite; } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } - public override void SetSize(long size) + public override Result SetSize(long size) { int oldBlockCount = (int)Util.DivideByRoundUp(_length, BlockSize); int newBlockCount = (int)Util.DivideByRoundUp(size, BlockSize); - if (oldBlockCount == newBlockCount) return; + if (oldBlockCount == newBlockCount) return Result.Success; if (oldBlockCount == 0) { @@ -97,7 +107,7 @@ namespace LibHac.Fs.Save _length = newBlockCount * BlockSize; - return; + return Result.Success; } if (newBlockCount == 0) @@ -107,7 +117,7 @@ namespace LibHac.Fs.Save InitialBlock = int.MinValue; _length = 0; - return; + return Result.Success; } if (newBlockCount > oldBlockCount) @@ -124,6 +134,8 @@ namespace LibHac.Fs.Save } _length = newBlockCount * BlockSize; + + return Result.Success; } } } diff --git a/src/LibHac/Fs/Save/DuplexStorage.cs b/src/LibHac/Fs/Save/DuplexStorage.cs index 890a519c..874af711 100644 --- a/src/LibHac/Fs/Save/DuplexStorage.cs +++ b/src/LibHac/Fs/Save/DuplexStorage.cs @@ -19,11 +19,13 @@ namespace LibHac.Fs.Save BitmapStorage = bitmap; BlockSize = blockSize; - Bitmap = new DuplexBitmap(BitmapStorage, (int)(bitmap.GetSize() * 8)); - _length = DataA.GetSize(); + bitmap.GetSize(out long bitmapSize).ThrowIfFailure(); + + Bitmap = new DuplexBitmap(BitmapStorage, (int)(bitmapSize * 8)); + DataA.GetSize(out _length).ThrowIfFailure(); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { long inPos = offset; int outPos = 0; @@ -38,15 +40,18 @@ namespace LibHac.Fs.Save IStorage data = Bitmap.Bitmap[blockNum] ? DataB : DataA; - data.Read(destination.Slice(outPos, bytesToRead), inPos); + Result rc = data.Read(inPos, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; remaining -= bytesToRead; } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long inPos = offset; int outPos = 0; @@ -61,26 +66,42 @@ namespace LibHac.Fs.Save IStorage data = Bitmap.Bitmap[blockNum] ? DataB : DataA; - data.Write(source.Slice(outPos, bytesToWrite), inPos); + Result rc = data.Write(inPos, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; remaining -= bytesToWrite; } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BitmapStorage?.Flush(); - DataA?.Flush(); - DataB?.Flush(); + Result rc = BitmapStorage.Flush(); + if (rc.IsFailure()) return rc; + + rc = DataA.Flush(); + if (rc.IsFailure()) return rc; + + rc = DataB.Flush(); + if (rc.IsFailure()) return rc; + + return Result.Success; } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } public void FsTrim() { - int blockCount = (int)(DataA.GetSize() / BlockSize); + DataA.GetSize(out long dataSize).ThrowIfFailure(); + + int blockCount = (int)(dataSize / BlockSize); for (int i = 0; i < blockCount; i++) { diff --git a/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs b/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs index df24abd4..75c6ecc8 100644 --- a/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs +++ b/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs @@ -29,25 +29,29 @@ namespace LibHac.Fs.Save } DataLayer = Layers[Layers.Length - 1]; - _length = DataLayer.GetSize(); + DataLayer.GetSize(out _length).ThrowIfFailure(); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - DataLayer.Read(destination, offset); + return DataLayer.Read(offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - DataLayer.Write(source, offset); + return DataLayer.Write(offset, source); } - public override void Flush() + public override Result Flush() { - DataLayer.Flush(); + return DataLayer.Flush(); } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } public void FsTrim() { diff --git a/src/LibHac/Fs/Save/JournalStorage.cs b/src/LibHac/Fs/Save/JournalStorage.cs index 91e4f809..ba4ac0bf 100644 --- a/src/LibHac/Fs/Save/JournalStorage.cs +++ b/src/LibHac/Fs/Save/JournalStorage.cs @@ -31,7 +31,7 @@ namespace LibHac.Fs.Save if (!leaveOpen) ToDispose.Add(baseStorage); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { long inPos = offset; int outPos = 0; @@ -46,15 +46,18 @@ namespace LibHac.Fs.Save int bytesToRead = Math.Min(remaining, BlockSize - blockPos); - BaseStorage.Read(destination.Slice(outPos, bytesToRead), physicalOffset); + Result rc = BaseStorage.Read(physicalOffset, destination.Slice(outPos, bytesToRead)); + if (rc.IsFailure()) return rc; outPos += bytesToRead; inPos += bytesToRead; remaining -= bytesToRead; } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { long inPos = offset; int outPos = 0; @@ -69,20 +72,27 @@ namespace LibHac.Fs.Save int bytesToWrite = Math.Min(remaining, BlockSize - blockPos); - BaseStorage.Write(source.Slice(outPos, bytesToWrite), physicalOffset); + Result rc = BaseStorage.Write(physicalOffset, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; remaining -= bytesToWrite; } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); diff --git a/src/LibHac/Fs/Save/RemapStorage.cs b/src/LibHac/Fs/Save/RemapStorage.cs index d1de2442..885691f4 100644 --- a/src/LibHac/Fs/Save/RemapStorage.cs +++ b/src/LibHac/Fs/Save/RemapStorage.cs @@ -46,9 +46,9 @@ namespace LibHac.Fs.Save Segments = InitSegments(Header, MapEntries); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { - if (destination.Length == 0) return; + if (destination.Length == 0) return Result.Success; MapEntry entry = GetMapEntry(offset); @@ -61,7 +61,7 @@ namespace LibHac.Fs.Save long entryPos = inPos - entry.VirtualOffset; int bytesToRead = (int)Math.Min(entry.VirtualOffsetEnd - inPos, remaining); - BaseStorage.Read(destination.Slice(outPos, bytesToRead), entry.PhysicalOffset + entryPos); + BaseStorage.Read(entry.PhysicalOffset + entryPos, destination.Slice(outPos, bytesToRead)); outPos += bytesToRead; inPos += bytesToRead; @@ -72,11 +72,13 @@ namespace LibHac.Fs.Save entry = entry.Next; } } + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { - if (source.Length == 0) return; + if (source.Length == 0) return Result.Success; MapEntry entry = GetMapEntry(offset); @@ -89,7 +91,9 @@ namespace LibHac.Fs.Save long entryPos = inPos - entry.VirtualOffset; int bytesToWrite = (int)Math.Min(entry.VirtualOffsetEnd - inPos, remaining); - BaseStorage.Write(source.Slice(outPos, bytesToWrite), entry.PhysicalOffset + entryPos); + + Result rc = BaseStorage.Write(entry.PhysicalOffset + entryPos, source.Slice(outPos, bytesToWrite)); + if (rc.IsFailure()) return rc; outPos += bytesToWrite; inPos += bytesToWrite; @@ -100,14 +104,21 @@ namespace LibHac.Fs.Save entry = entry.Next; } } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => -1; + public override Result GetSize(out long size) + { + // todo: Different result code + size = -1; + return Result.Success; + } public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); @@ -199,7 +210,7 @@ namespace LibHac.Fs.Save public class RemapHeader { public string Magic { get; } - public uint Verison { get; } + public uint Version { get; } public int MapEntryCount { get; } public int MapSegmentCount { get; } public int SegmentBits { get; } @@ -209,7 +220,7 @@ namespace LibHac.Fs.Save var reader = new BinaryReader(storage.AsStream()); Magic = reader.ReadAscii(4); - Verison = reader.ReadUInt32(); + Version = reader.ReadUInt32(); MapEntryCount = reader.ReadInt32(); MapSegmentCount = reader.ReadInt32(); SegmentBits = reader.ReadInt32(); diff --git a/src/LibHac/Fs/Save/SaveDataFile.cs b/src/LibHac/Fs/Save/SaveDataFile.cs index c6ba6bf1..784350d9 100644 --- a/src/LibHac/Fs/Save/SaveDataFile.cs +++ b/src/LibHac/Fs/Save/SaveDataFile.cs @@ -19,43 +19,51 @@ namespace LibHac.Fs.Save Size = size; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + int toRead = ValidateReadParamsAndGetSize(destination, offset); - BaseStorage.Read(destination.Slice(0, toRead), offset); + Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + if (rc.IsFailure()) return rc; - return toRead; + bytesRead = toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - BaseStorage.Write(source, offset); + BaseStorage.Write(offset, source); if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return Size; + size = Size; + return Result.Success; } - public override void SetSize(long size) + public override Result SetSize(long size) { if (size < 0) throw new ArgumentOutOfRangeException(nameof(size)); - if (Size == size) return; + if (Size == size) return Result.Success; - BaseStorage.SetSize(size); + Result rc = BaseStorage.SetSize(size); + if (rc.IsFailure()) return rc; if (!FileTable.TryOpenFile(Path, out SaveFileInfo fileInfo)) { @@ -68,6 +76,8 @@ namespace LibHac.Fs.Save FileTable.AddFile(Path, ref fileInfo); Size = size; + + return Result.Success; } } } diff --git a/src/LibHac/Fs/Save/SaveFsList.cs b/src/LibHac/Fs/Save/SaveFsList.cs index 0bf9d428..7870b119 100644 --- a/src/LibHac/Fs/Save/SaveFsList.cs +++ b/src/LibHac/Fs/Save/SaveFsList.cs @@ -101,10 +101,10 @@ namespace LibHac.Fs.Save if (capacity == 0 || length >= capacity) { - long currentSize = Storage.GetSize(); + Storage.GetSize(out long currentSize).ThrowIfFailure(); Storage.SetSize(currentSize + CapacityIncrement); - long newSize = Storage.GetSize(); + Storage.GetSize(out long newSize).ThrowIfFailure(); SetListCapacity((int)(newSize / _sizeOfEntry)); } @@ -282,7 +282,7 @@ namespace LibHac.Fs.Save private int GetListCapacity() { Span buf = stackalloc byte[sizeof(int)]; - Storage.Read(buf, 4); + Storage.Read(4, buf).ThrowIfFailure(); return MemoryMarshal.Read(buf); } @@ -290,7 +290,7 @@ namespace LibHac.Fs.Save private int GetListLength() { Span buf = stackalloc byte[sizeof(int)]; - Storage.Read(buf, 0); + Storage.Read(0, buf).ThrowIfFailure(); return MemoryMarshal.Read(buf); } @@ -300,7 +300,7 @@ namespace LibHac.Fs.Save Span buf = stackalloc byte[sizeof(int)]; MemoryMarshal.Write(buf, ref capacity); - Storage.Write(buf, 4); + Storage.Write(4, buf).ThrowIfFailure(); } private void SetListLength(int length) @@ -308,7 +308,7 @@ namespace LibHac.Fs.Save Span buf = stackalloc byte[sizeof(int)]; MemoryMarshal.Write(buf, ref length); - Storage.Write(buf, 0); + Storage.Write(0, buf).ThrowIfFailure(); } private void ReadEntry(int index, out SaveFsEntry entry) @@ -352,7 +352,7 @@ namespace LibHac.Fs.Save Debug.Assert(entry.Length == _sizeOfEntry); int offset = index * _sizeOfEntry; - Storage.Read(entry, offset); + Storage.Read(offset, entry); } private void WriteEntry(int index, Span entry) @@ -360,7 +360,7 @@ namespace LibHac.Fs.Save Debug.Assert(entry.Length == _sizeOfEntry); int offset = index * _sizeOfEntry; - Storage.Write(entry, offset); + Storage.Write(offset, entry); } private ref SaveFsEntry GetEntryFromBytes(Span entry) diff --git a/src/LibHac/Fs/SectorStorage.cs b/src/LibHac/Fs/SectorStorage.cs index 7e3efee7..16ef4898 100644 --- a/src/LibHac/Fs/SectorStorage.cs +++ b/src/LibHac/Fs/SectorStorage.cs @@ -15,37 +15,50 @@ namespace LibHac.Fs { BaseStorage = baseStorage; SectorSize = sectorSize; - SectorCount = (int)Util.DivideByRoundUp(BaseStorage.GetSize(), SectorSize); - _length = BaseStorage.GetSize(); + + baseStorage.GetSize(out long baseSize).ThrowIfFailure(); + + SectorCount = (int)Util.DivideByRoundUp(baseSize, SectorSize); + _length = baseSize; if (!leaveOpen) ToDispose.Add(BaseStorage); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { ValidateSize(destination.Length, offset); - BaseStorage.Read(destination, offset); + return BaseStorage.Read(offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { ValidateSize(source.Length, offset); - BaseStorage.Write(source, offset); + return BaseStorage.Write(offset, source); } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - BaseStorage.SetSize(size); + size = _length; + return Result.Success; + } - SectorCount = (int)Util.DivideByRoundUp(BaseStorage.GetSize(), SectorSize); - _length = BaseStorage.GetSize(); + public override Result SetSize(long size) + { + Result rc = BaseStorage.SetSize(size); + if (rc.IsFailure()) return rc; + + rc = BaseStorage.GetSize(out long newSize); + if (rc.IsFailure()) return rc; + + SectorCount = (int)Util.DivideByRoundUp(newSize, SectorSize); + _length = newSize; + + return Result.Success; } /// diff --git a/src/LibHac/Fs/StorageExtensions.cs b/src/LibHac/Fs/StorageExtensions.cs index 16340ecf..a1f64dc7 100644 --- a/src/LibHac/Fs/StorageExtensions.cs +++ b/src/LibHac/Fs/StorageExtensions.cs @@ -7,15 +7,16 @@ namespace LibHac.Fs { public static class StorageExtensions { - public static void Read(this IStorage storage, byte[] buffer, long offset, int count, int bufferOffset) + public static Result Read(this IStorage storage, long offset, byte[] buffer, int count, int bufferOffset) { ValidateStorageParameters(buffer, offset, count, bufferOffset); - storage.Read(buffer.AsSpan(bufferOffset, count), offset); + return storage.Read(offset, buffer.AsSpan(bufferOffset, count)); } - public static void Write(this IStorage storage, byte[] buffer, long offset, int count, int bufferOffset) + + public static Result Write(this IStorage storage, long offset, byte[] buffer, int count, int bufferOffset) { ValidateStorageParameters(buffer, offset, count, bufferOffset); - storage.Write(buffer.AsSpan(bufferOffset, count), offset); + return storage.Write(offset, buffer.AsSpan(bufferOffset, count)); } private static void ValidateStorageParameters(byte[] buffer, long offset, int count, int bufferOffset) @@ -28,7 +29,7 @@ namespace LibHac.Fs public static IStorage Slice(this IStorage storage, long start) { - long length = storage.GetSize(); + storage.GetSize(out long length).ThrowIfFailure(); if (length == -1) { @@ -53,10 +54,10 @@ namespace LibHac.Fs return storage.AsReadOnly(true); } - // Todo: Move out of SubStorage public static IStorage AsReadOnly(this IStorage storage, bool leaveOpen) { - return new SubStorage(storage, 0, storage.GetSize(), leaveOpen, FileAccess.Read); + storage.GetSize(out long storageSize).ThrowIfFailure(); + return new SubStorage(storage, 0, storageSize, leaveOpen, FileAccess.Read); } public static Stream AsStream(this IStorage storage) => new StorageStream(storage, FileAccess.ReadWrite, true); @@ -68,7 +69,11 @@ namespace LibHac.Fs public static void CopyTo(this IStorage input, IStorage output, IProgressReport progress = null) { const int bufferSize = 81920; - long remaining = Math.Min(input.GetSize(), output.GetSize()); + + input.GetSize(out long inputSize).ThrowIfFailure(); + output.GetSize(out long outputSize).ThrowIfFailure(); + + long remaining = Math.Min(inputSize, outputSize); if (remaining < 0) throw new ArgumentException("Storage must have an explicit length"); progress?.SetTotal(remaining); @@ -81,8 +86,8 @@ namespace LibHac.Fs { int toCopy = (int)Math.Min(bufferSize, remaining); Span buf = buffer.AsSpan(0, toCopy); - input.Read(buf, pos); - output.Write(buf, pos); + input.Read(pos, buf); + output.Write(pos, buf); remaining -= toCopy; pos += toCopy; @@ -100,7 +105,8 @@ namespace LibHac.Fs public static void Fill(this IStorage input, byte value, IProgressReport progress = null) { - input.Fill(value, 0, input.GetSize(), progress); + input.GetSize(out long inputSize).ThrowIfFailure(); + input.Fill(value, 0, inputSize, progress); } public static void Fill(this IStorage input, byte value, long offset, long count, IProgressReport progress = null) @@ -116,7 +122,7 @@ namespace LibHac.Fs Span buf = stackalloc byte[(int)count]; buf.Fill(value); - input.Write(buf, offset); + input.Write(offset, buf); } private static void FillLarge(this IStorage input, byte value, long offset, long count, IProgressReport progress = null) @@ -139,7 +145,7 @@ namespace LibHac.Fs int toFill = (int)Math.Min(bufferSize, remaining); Span buf = buffer.AsSpan(0, toFill); - input.Write(buf, pos); + input.Write(pos, buf); remaining -= toFill; pos += toFill; @@ -157,9 +163,11 @@ namespace LibHac.Fs public static void WriteAllBytes(this IStorage input, string filename, IProgressReport progress = null) { + input.GetSize(out long inputSize).ThrowIfFailure(); + using (var outFile = new FileStream(filename, FileMode.Create, FileAccess.Write)) { - input.CopyToStream(outFile, input.GetSize(), progress); + input.CopyToStream(outFile, inputSize, progress); } } @@ -167,7 +175,9 @@ namespace LibHac.Fs { if (storage == null) return new byte[0]; - var arr = new byte[storage.GetSize()]; + storage.GetSize(out long storageSize).ThrowIfFailure(); + + var arr = new byte[storageSize]; storage.CopyTo(new MemoryStorage(arr)); return arr; } @@ -176,10 +186,12 @@ namespace LibHac.Fs { if (storage == null) return new T[0]; - var arr = new T[storage.GetSize() / Marshal.SizeOf()]; + storage.GetSize(out long storageSize).ThrowIfFailure(); + + var arr = new T[storageSize / Marshal.SizeOf()]; Span dest = MemoryMarshal.Cast(arr.AsSpan()); - storage.Read(dest, 0); + storage.Read(0, dest); return arr; } @@ -194,7 +206,7 @@ namespace LibHac.Fs while (remaining > 0) { int toWrite = (int)Math.Min(buffer.Length, remaining); - input.Read(buffer.AsSpan(0, toWrite), inOffset); + input.Read(inOffset, buffer.AsSpan(0, toWrite)); output.Write(buffer, 0, toWrite); remaining -= toWrite; @@ -203,7 +215,11 @@ namespace LibHac.Fs } } - public static void CopyToStream(this IStorage input, Stream output) => CopyToStream(input, output, input.GetSize()); + public static void CopyToStream(this IStorage input, Stream output) + { + input.GetSize(out long inputSize).ThrowIfFailure(); + CopyToStream(input, output, inputSize); + } public static IStorage AsStorage(this Stream stream) { diff --git a/src/LibHac/Fs/StorageFile.cs b/src/LibHac/Fs/StorageFile.cs index ce362ebe..176abdc5 100644 --- a/src/LibHac/Fs/StorageFile.cs +++ b/src/LibHac/Fs/StorageFile.cs @@ -12,40 +12,46 @@ namespace LibHac.Fs Mode = mode; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; int toRead = ValidateReadParamsAndGetSize(destination, offset); - BaseStorage.Read(destination.Slice(0, toRead), offset); + Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + if (rc.IsFailure()) return rc; - return toRead; + bytesRead = toRead; + return Result.Success; } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { ValidateWriteParams(source, offset); - BaseStorage.Write(source, offset); + Result rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() + public override Result GetSize(out long size) { - return BaseStorage.GetSize(); + return BaseStorage.GetSize(out size); } - public override void SetSize(long size) + public override Result SetSize(long size) { - BaseStorage.SetSize(size); + return BaseStorage.SetSize(size); } } } diff --git a/src/LibHac/Fs/StorageStream.cs b/src/LibHac/Fs/StorageStream.cs index bbd3d6e9..85cbef72 100644 --- a/src/LibHac/Fs/StorageStream.cs +++ b/src/LibHac/Fs/StorageStream.cs @@ -13,7 +13,8 @@ namespace LibHac.Fs { BaseStorage = baseStorage; LeaveOpen = leaveOpen; - _length = baseStorage.GetSize(); + + baseStorage.GetSize(out _length).ThrowIfFailure(); CanRead = access.HasFlag(FileAccess.Read); CanWrite = access.HasFlag(FileAccess.Write); @@ -22,7 +23,7 @@ namespace LibHac.Fs public override int Read(byte[] buffer, int offset, int count) { int toRead = (int)Math.Min(count, Length - Position); - BaseStorage.Read(buffer.AsSpan(offset, toRead), Position); + BaseStorage.Read(Position, buffer.AsSpan(offset, toRead)).ThrowIfFailure(); Position += toRead; return toRead; @@ -30,7 +31,7 @@ namespace LibHac.Fs public override void Write(byte[] buffer, int offset, int count) { - BaseStorage.Write(buffer.AsSpan(offset, count), Position); + BaseStorage.Write(Position, buffer.AsSpan(offset, count)).ThrowIfFailure(); Position += count; } @@ -59,9 +60,9 @@ namespace LibHac.Fs public override void SetLength(long value) { - BaseStorage.SetSize(value); + BaseStorage.SetSize(value).ThrowIfFailure(); - _length = BaseStorage.GetSize(); + BaseStorage.GetSize(out _length).ThrowIfFailure(); } public override bool CanRead { get; } diff --git a/src/LibHac/Fs/StreamFile.cs b/src/LibHac/Fs/StreamFile.cs index e81b642f..ba7305db 100644 --- a/src/LibHac/Fs/StreamFile.cs +++ b/src/LibHac/Fs/StreamFile.cs @@ -12,6 +12,8 @@ namespace LibHac.Fs /// public class StreamFile : FileBase { + // todo: handle Stream exceptions + private Stream BaseStream { get; } private object Locker { get; } = new object(); @@ -21,7 +23,7 @@ namespace LibHac.Fs Mode = mode; } - public override int Read(Span destination, long offset, ReadOption options) + public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { #if STREAM_SPAN lock (Locker) @@ -31,13 +33,13 @@ namespace LibHac.Fs BaseStream.Position = offset; } - return BaseStream.Read(destination); + bytesRead = BaseStream.Read(destination); + return Result.Success; } #else byte[] buffer = ArrayPool.Shared.Rent(destination.Length); try { - int bytesRead; lock (Locker) { if (BaseStream.Position != offset) @@ -50,13 +52,13 @@ namespace LibHac.Fs new Span(buffer, 0, destination.Length).CopyTo(destination); - return bytesRead; + return Result.Success; } finally { ArrayPool.Shared.Return(buffer); } #endif } - public override void Write(ReadOnlySpan source, long offset, WriteOption options) + public override Result Write(long offset, ReadOnlySpan source, WriteOption options) { #if STREAM_SPAN lock (Locker) @@ -81,31 +83,36 @@ namespace LibHac.Fs if ((options & WriteOption.Flush) != 0) { - Flush(); + return Flush(); } + + return Result.Success; } - public override void Flush() + public override Result Flush() { lock (Locker) { BaseStream.Flush(); + return Result.Success; } } - public override long GetSize() + public override Result GetSize(out long size) { lock (Locker) { - return BaseStream.Length; + size = BaseStream.Length; + return Result.Success; } } - public override void SetSize(long size) + public override Result SetSize(long size) { lock (Locker) { BaseStream.SetLength(size); + return Result.Success; } } } diff --git a/src/LibHac/Fs/StreamStorage.cs b/src/LibHac/Fs/StreamStorage.cs index 154caa51..4784da48 100644 --- a/src/LibHac/Fs/StreamStorage.cs +++ b/src/LibHac/Fs/StreamStorage.cs @@ -9,6 +9,8 @@ namespace LibHac.Fs { public class StreamStorage : StorageBase { + // todo: handle Stream exceptions + private Stream BaseStream { get; } private object Locker { get; } = new object(); private long _length; @@ -20,7 +22,7 @@ namespace LibHac.Fs if (!leaveOpen) ToDispose.Add(BaseStream); } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { #if STREAM_SPAN lock (Locker) @@ -50,9 +52,11 @@ namespace LibHac.Fs } finally { ArrayPool.Shared.Return(buffer); } #endif + + return Result.Success; } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { #if STREAM_SPAN lock (Locker) @@ -82,16 +86,24 @@ namespace LibHac.Fs } finally { ArrayPool.Shared.Return(buffer); } #endif + + return Result.Success; } - public override void Flush() + public override Result Flush() { lock (Locker) { BaseStream.Flush(); + + return Result.Success; } } - public override long GetSize() => _length; + public override Result GetSize(out long size) + { + size = _length; + return Result.Success; + } } } diff --git a/src/LibHac/Fs/SubStorage.cs b/src/LibHac/Fs/SubStorage.cs index 710cce14..144b7ab0 100644 --- a/src/LibHac/Fs/SubStorage.cs +++ b/src/LibHac/Fs/SubStorage.cs @@ -36,41 +36,53 @@ namespace LibHac.Fs Access = access; } - protected override void ReadImpl(Span destination, long offset) + protected override Result ReadImpl(long offset, Span destination) { if ((Access & FileAccess.Read) == 0) throw new InvalidOperationException("Storage is not readable"); - BaseStorage.Read(destination, offset + Offset); + return BaseStorage.Read(offset + Offset, destination); } - protected override void WriteImpl(ReadOnlySpan source, long offset) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { if ((Access & FileAccess.Write) == 0) throw new InvalidOperationException("Storage is not writable"); - BaseStorage.Write(source, offset + Offset); + return BaseStorage.Write(offset + Offset, source); } - public override void Flush() + public override Result Flush() { - BaseStorage.Flush(); + return BaseStorage.Flush(); } - public override long GetSize() => _length; - - public override void SetSize(long size) + public override Result GetSize(out long size) { - //if (!IsResizable) - // return 0x313802; + size = _length; + return Result.Success; + } - //if (Offset < 0 || size < 0) - // return 0x2F5C02; + public override Result SetSize(long size) + { + if (BaseStorage == null) return ResultFs.Result6902.Log(); - if (BaseStorage.GetSize() != Offset + _length) + // todo: Add IsResizable member + // if (!IsResizable) return ResultFs.SubStorageNotResizable.Log(); + + if (Offset < 0 || size < 0) return ResultFs.InvalidSize.Log(); + + Result rc = BaseStorage.GetSize(out long baseSize); + if (rc.IsFailure()) return rc; + + if (baseSize != Offset + _length) { - throw new NotSupportedException("SubStorage cannot be resized unless it is located at the end of the base storage."); + // SubStorage cannot be resized unless it is located at the end of the base storage. + return ResultFs.SubStorageNotResizableMiddleOfFile.Log(); } - BaseStorage.SetSize(Offset + size); + rc = BaseStorage.SetSize(Offset + size); + if (rc.IsFailure()) return rc; _length = size; + + return Result.Success; } } } diff --git a/src/LibHac/FsClient/Accessors/FileAccessor.cs b/src/LibHac/FsClient/Accessors/FileAccessor.cs index f69bec1f..9624c6ec 100644 --- a/src/LibHac/FsClient/Accessors/FileAccessor.cs +++ b/src/LibHac/FsClient/Accessors/FileAccessor.cs @@ -12,8 +12,9 @@ namespace LibHac.FsClient.Accessors public OpenMode OpenMode { get; } // Todo: Consider removing Mode from interface because OpenMode is in FileAccessor + // Todo: Set WriteState to Error based on returned results OpenMode IFile.Mode => OpenMode; - + public FileAccessor(IFile baseFile, FileSystemAccessor parent, OpenMode mode) { File = baseFile; @@ -21,14 +22,14 @@ namespace LibHac.FsClient.Accessors OpenMode = mode; } - public int Read(Span destination, long offset, ReadOption options) + public Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { CheckIfDisposed(); - return File.Read(destination, offset, options); + return File.Read(out bytesRead, offset, destination, options); } - public void Write(ReadOnlySpan source, long offset, WriteOption options) + public Result Write(long offset, ReadOnlySpan source, WriteOption options) { CheckIfDisposed(); @@ -36,35 +37,46 @@ namespace LibHac.FsClient.Accessors { WriteState = (WriteState)(~options & WriteOption.Flush); - return; + return Result.Success; } - File.Write(source, offset, options); + // + Result rc = File.Write(offset, source, options); - WriteState = (WriteState)(~options & WriteOption.Flush); + if (rc.IsSuccess()) + { + WriteState = (WriteState)(~options & WriteOption.Flush); + } + + return rc; } - public void Flush() + public Result Flush() { CheckIfDisposed(); - File.Flush(); + Result rc = File.Flush(); - WriteState = WriteState.None; + if (rc.IsSuccess()) + { + WriteState = WriteState.None; + } + + return rc; } - public long GetSize() + public Result GetSize(out long size) { CheckIfDisposed(); - return File.GetSize(); + return File.GetSize(out size); } - public void SetSize(long size) + public Result SetSize(long size) { CheckIfDisposed(); - File.SetSize(size); + return File.SetSize(size); } public void Dispose() @@ -75,7 +87,7 @@ namespace LibHac.FsClient.Accessors { // Original FS code would return an error: // ThrowHelper.ThrowResult(ResultsFs.ResultFsWriteStateUnflushed); - + Flush(); } diff --git a/src/LibHac/FsClient/FileSystemManager.cs b/src/LibHac/FsClient/FileSystemManager.cs index ecd228d0..10ca268f 100644 --- a/src/LibHac/FsClient/FileSystemManager.cs +++ b/src/LibHac/FsClient/FileSystemManager.cs @@ -364,22 +364,22 @@ namespace LibHac.FsClient public int ReadFile(FileHandle handle, Span destination, long offset, ReadOption option) { - int bytesRead; + long bytesRead; if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - bytesRead = handle.File.Read(destination, offset, option); + handle.File.Read(out bytesRead, offset, destination, option).ThrowIfFailure(); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, handle, $", offset: {offset}, size: {destination.Length}"); } else { - bytesRead = handle.File.Read(destination, offset, option); + handle.File.Read(out bytesRead, offset, destination, option).ThrowIfFailure(); } - return bytesRead; + return (int)bytesRead; } public void WriteFile(FileHandle handle, ReadOnlySpan source, long offset) @@ -392,7 +392,7 @@ namespace LibHac.FsClient if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.Write(source, offset, option); + handle.File.Write(offset, source, option); TimeSpan endTime = Time.GetCurrent(); string optionString = (option & WriteOption.Flush) == 0 ? "" : $", write_option: {option}"; @@ -401,7 +401,7 @@ namespace LibHac.FsClient } else { - handle.File.Write(source, offset, option); + handle.File.Write(offset, source, option); } } @@ -423,7 +423,9 @@ namespace LibHac.FsClient public long GetFileSize(FileHandle handle) { - return handle.File.GetSize(); + handle.File.GetSize(out long fileSize).ThrowIfFailure(); + + return fileSize; } public void SetFileSize(FileHandle handle, long size) @@ -501,16 +503,16 @@ namespace LibHac.FsClient handle.Directory.Dispose(); } } - + internal Result FindFileSystem(ReadOnlySpan path, out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) { fileSystem = default; - Result result = GetMountName(path, out ReadOnlySpan mountName, out subPath); - if (result.IsFailure()) return result; + Result rc = GetMountName(path, out ReadOnlySpan mountName, out subPath); + if (rc.IsFailure()) return rc; - result = MountTable.Find(mountName.ToString(), out fileSystem); - if (result.IsFailure()) return result; + rc = MountTable.Find(mountName.ToString(), out fileSystem); + if (rc.IsFailure()) return rc; return Result.Success; } diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs index 3f9c4d99..edba44ca 100644 --- a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs @@ -37,10 +37,10 @@ namespace LibHac.FsService.Creators string partitionPath = GetPartitionPath(partitionId); - Result subFsResult = + Result rc = Util.CreateSubFileSystem(out IFileSystem subFileSystem, Config.RootFileSystem, partitionPath, true); - if (subFsResult.IsFailure()) return subFsResult; + if (rc.IsFailure()) return rc; if (rootPath == string.Empty) { diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index f43fca19..80da9c15 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -103,9 +103,9 @@ namespace LibHac.FsService if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log(); - Result saveFsResult = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out ulong saveDataId, spaceId, + Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out ulong saveDataId, spaceId, attribute, false, true); - if (saveFsResult.IsFailure()) return saveFsResult.Log(); + if (rc.IsFailure()) return rc; // Missing check if the current title owns the save data or can open it @@ -121,8 +121,8 @@ namespace LibHac.FsService // Missing permission check - Result res = FsProxyCore.SetSdCardEncryptionSeed(seed); - if (res.IsFailure()) return res; + Result rc = FsProxyCore.SetSdCardEncryptionSeed(seed); + if (rc.IsFailure()) return rc; // todo: Reset save data indexer diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 6f1a67a7..8c3e0e16 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -35,35 +35,35 @@ namespace LibHac.FsService string contentDirPath = default; IFileSystem baseFileSystem = default; bool isEncrypted = false; - Result baseFsResult; + Result rc; switch (storageId) { case ContentStorageId.System: - baseFsResult = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.System); + rc = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.System); contentDirPath = $"/{ContentDirectoryName}"; break; case ContentStorageId.User: - baseFsResult = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.User); + rc = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.User); contentDirPath = $"/{ContentDirectoryName}"; break; case ContentStorageId.SdCard: - baseFsResult = OpenSdCardFileSystem(out baseFileSystem); + rc = OpenSdCardFileSystem(out baseFileSystem); contentDirPath = $"/{NintendoDirectoryName}/{ContentDirectoryName}"; isEncrypted = true; break; default: - baseFsResult = ResultFs.InvalidArgument; + rc = ResultFs.InvalidArgument; break; } - if (baseFsResult.IsFailure()) return baseFsResult; + if (rc.IsFailure()) return rc; baseFileSystem.EnsureDirectoryExists(contentDirPath); - Result subFsResult = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFileSystem, + rc = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFileSystem, baseFileSystem, contentDirPath); - if (subFsResult.IsFailure()) return subFsResult; + if (rc.IsFailure()) return rc; if (!isEncrypted) { @@ -93,8 +93,8 @@ namespace LibHac.FsService { fileSystem = default; - Result openSaveDirResult = OpenSaveDataDirectory(out IFileSystem saveDirFs, spaceId, saveDataRootPath, true); - if (openSaveDirResult.IsFailure()) return openSaveDirResult.Log(); + Result rc = OpenSaveDataDirectory(out IFileSystem saveDirFs, spaceId, saveDataRootPath, true); + if (rc.IsFailure()) return rc; bool allowDirectorySaveData = AllowDirectorySaveData(spaceId, saveDataRootPath); bool useDeviceUniqueMac = Util.UseDeviceUniqueSaveMac(spaceId); @@ -113,11 +113,11 @@ namespace LibHac.FsService // Missing save FS cache lookup - Result saveFsResult = FsCreators.SaveDataFileSystemCreator.Create(out IFileSystem saveFs, + rc = FsCreators.SaveDataFileSystemCreator.Create(out IFileSystem saveFs, out ISaveDataExtraDataAccessor extraDataAccessor, saveDirFs, saveDataId, allowDirectorySaveData, useDeviceUniqueMac, type, null); - if (saveFsResult.IsFailure()) return saveFsResult.Log(); + if (rc.IsFailure()) return rc; if (cacheExtraData) { @@ -133,12 +133,12 @@ namespace LibHac.FsService { if (openOnHostFs && AllowDirectorySaveData(spaceId, saveDataRootPath)) { - Result hostFsResult = FsCreators.TargetManagerFileSystemCreator.Create(out IFileSystem hostFs, false); + Result rc = FsCreators.TargetManagerFileSystemCreator.Create(out IFileSystem hostFs, false); - if (hostFsResult.IsFailure()) + if (rc.IsFailure()) { fileSystem = default; - return hostFsResult.Log(); + return rc; } return Util.CreateSubFileSystem(out fileSystem, hostFs, saveDataRootPath, true); @@ -152,44 +152,45 @@ namespace LibHac.FsService public Result OpenSaveDataDirectoryImpl(out IFileSystem fileSystem, SaveDataSpaceId spaceId, string saveDirName, bool createIfMissing) { fileSystem = default; + Result rc; switch (spaceId) { case SaveDataSpaceId.System: - Result sysFsResult = OpenBisFileSystem(out IFileSystem sysFs, string.Empty, BisPartitionId.System); - if (sysFsResult.IsFailure()) return sysFsResult.Log(); + rc = OpenBisFileSystem(out IFileSystem sysFs, string.Empty, BisPartitionId.System); + if (rc.IsFailure()) return rc; return Util.CreateSubFileSystem(out fileSystem, sysFs, saveDirName, createIfMissing); case SaveDataSpaceId.User: case SaveDataSpaceId.TemporaryStorage: - Result userFsResult = OpenBisFileSystem(out IFileSystem userFs, string.Empty, BisPartitionId.System); - if (userFsResult.IsFailure()) return userFsResult.Log(); + rc = OpenBisFileSystem(out IFileSystem userFs, string.Empty, BisPartitionId.User); + if (rc.IsFailure()) return rc; return Util.CreateSubFileSystem(out fileSystem, userFs, saveDirName, createIfMissing); case SaveDataSpaceId.SdSystem: case SaveDataSpaceId.SdCache: - Result sdFsResult = OpenSdCardFileSystem(out IFileSystem sdFs); - if (sdFsResult.IsFailure()) return sdFsResult.Log(); + rc = OpenSdCardFileSystem(out IFileSystem sdFs); + if (rc.IsFailure()) return rc; string sdSaveDirPath = $"/{NintendoDirectoryName}{saveDirName}"; - Result sdSubResult = Util.CreateSubFileSystem(out IFileSystem sdSubFs, sdFs, sdSaveDirPath, createIfMissing); - if (sdSubResult.IsFailure()) return sdSubResult.Log(); + rc = Util.CreateSubFileSystem(out IFileSystem sdSubFs, sdFs, sdSaveDirPath, createIfMissing); + if (rc.IsFailure()) return rc; return FsCreators.EncryptedFileSystemCreator.Create(out fileSystem, sdSubFs, EncryptedFsKeyId.Save, SdEncryptionSeed); case SaveDataSpaceId.ProperSystem: - Result sysProperFsResult = OpenBisFileSystem(out IFileSystem sysProperFs, string.Empty, BisPartitionId.SystemProperPartition); - if (sysProperFsResult.IsFailure()) return sysProperFsResult.Log(); + rc = OpenBisFileSystem(out IFileSystem sysProperFs, string.Empty, BisPartitionId.SystemProperPartition); + if (rc.IsFailure()) return rc; return Util.CreateSubFileSystem(out fileSystem, sysProperFs, saveDirName, createIfMissing); case SaveDataSpaceId.Safe: - Result safeFsResult = OpenBisFileSystem(out IFileSystem safeFs, string.Empty, BisPartitionId.SafeMode); - if (safeFsResult.IsFailure()) return safeFsResult.Log(); + rc = OpenBisFileSystem(out IFileSystem safeFs, string.Empty, BisPartitionId.SafeMode); + if (rc.IsFailure()) return rc; return Util.CreateSubFileSystem(out fileSystem, safeFs, saveDirName, createIfMissing); diff --git a/src/LibHac/Keyset.cs b/src/LibHac/Keyset.cs index 39b5538a..d48e625e 100644 --- a/src/LibHac/Keyset.cs +++ b/src/LibHac/Keyset.cs @@ -198,7 +198,7 @@ namespace LibHac using (var keyblobDec = new Aes128CtrStorage( new MemoryStorage(EncryptedKeyblobs[i], 0x20, Keyblobs[i].Length), KeyblobKeys[i], counter, false)) { - keyblobDec.Read(Keyblobs[i], 0); + keyblobDec.Read(0, Keyblobs[i]).ThrowIfFailure(); } } } diff --git a/src/LibHac/Kip.cs b/src/LibHac/Kip.cs index 0c154694..f007713d 100644 --- a/src/LibHac/Kip.cs +++ b/src/LibHac/Kip.cs @@ -43,9 +43,11 @@ namespace LibHac public byte[] DecompressSection(int index) { - IStorage compStream = OpenSection(index); - var compressed = new byte[compStream.GetSize()]; - compStream.Read(compressed, 0); + IStorage compStorage = OpenSection(index); + compStorage.GetSize(out long compressedSize).ThrowIfFailure(); + + var compressed = new byte[compressedSize]; + compStorage.Read(0, compressed).ThrowIfFailure(); return DecompressBlz(compressed); } diff --git a/src/LibHac/Kvdb/ImkvdbReader.cs b/src/LibHac/Kvdb/ImkvdbReader.cs index 28556809..e0d96df1 100644 --- a/src/LibHac/Kvdb/ImkvdbReader.cs +++ b/src/LibHac/Kvdb/ImkvdbReader.cs @@ -58,8 +58,8 @@ namespace LibHac.Kvdb key = default; value = default; - Result sizeResult = GetEntrySize(out int keySize, out int valueSize); - if (sizeResult.IsFailure()) return sizeResult; + Result rc = GetEntrySize(out int keySize, out int valueSize); + if (rc.IsFailure()) return rc; _position += Unsafe.SizeOf(); diff --git a/src/LibHac/Kvdb/KeyValueDatabase.cs b/src/LibHac/Kvdb/KeyValueDatabase.cs index f92d00fe..e2043074 100644 --- a/src/LibHac/Kvdb/KeyValueDatabase.cs +++ b/src/LibHac/Kvdb/KeyValueDatabase.cs @@ -37,13 +37,13 @@ namespace LibHac.Kvdb { var reader = new ImkvdbReader(data); - Result headerResult = reader.ReadHeader(out int entryCount); - if (headerResult.IsFailure()) return headerResult; + Result rc = reader.ReadHeader(out int entryCount); + if (rc.IsFailure()) return rc; for (int i = 0; i < entryCount; i++) { - Result entryResult = reader.ReadEntry(out ReadOnlySpan keyBytes, out ReadOnlySpan valueBytes); - if (entryResult.IsFailure()) return entryResult; + rc = reader.ReadEntry(out ReadOnlySpan keyBytes, out ReadOnlySpan valueBytes); + if (rc.IsFailure()) return rc; var key = new TKey(); var value = new TValue(); diff --git a/src/LibHac/Nro.cs b/src/LibHac/Nro.cs index 2e09ea80..c3e301db 100644 --- a/src/LibHac/Nro.cs +++ b/src/LibHac/Nro.cs @@ -21,7 +21,9 @@ namespace LibHac if (Header.Magic != "NRO0") throw new InvalidDataException("NRO0 magic is incorrect!"); - if (Header.Size < Storage.GetSize()) + Storage.GetSize(out long storageSize).ThrowIfFailure(); + + if (Header.Size < storageSize) { AssetStorage = Storage.Slice(Header.Size); var assetReader = new BinaryReader(AssetStorage.AsStream()); diff --git a/src/LibHac/Nso.cs b/src/LibHac/Nso.cs index d60a76ca..53c35063 100644 --- a/src/LibHac/Nso.cs +++ b/src/LibHac/Nso.cs @@ -82,7 +82,7 @@ namespace LibHac public byte[] DecompressSection() { var compressed = new byte[CompressedSize]; - OpenSection().Read(compressed, 0); + OpenSection().Read(0, compressed).ThrowIfFailure(); if (IsCompressed) return Lz4.Decompress(compressed, (int)DecompressedSize); diff --git a/src/LibHac/Package1.cs b/src/LibHac/Package1.cs index 6f57cf98..0c4efc20 100644 --- a/src/LibHac/Package1.cs +++ b/src/LibHac/Package1.cs @@ -40,7 +40,7 @@ namespace LibHac for (int i = 0; i < 0x20; i++) { var dec = new Aes128CtrStorage(encStorage, keyset.Package1Keys[i], Counter, true); - dec.Read(decBuffer, 0); + dec.Read(0, decBuffer).ThrowIfFailure(); if (BitConverter.ToUInt32(decBuffer, 0) == Pk11Magic) { diff --git a/src/LibHac/Package2.cs b/src/LibHac/Package2.cs index 9714bc25..943dab71 100644 --- a/src/LibHac/Package2.cs +++ b/src/LibHac/Package2.cs @@ -109,12 +109,12 @@ namespace LibHac var counter = new byte[0x10]; var decBuffer = new byte[0x10]; - storage.Read(counter, 0x100); + storage.Read(0x100, counter).ThrowIfFailure(); for (int i = 0; i < 0x20; i++) { var dec = new Aes128CtrStorage(storage.Slice(0x100), keyset.Package2Keys[i], counter, false); - dec.Read(decBuffer, 0x50); + dec.Read(0x50, decBuffer).ThrowIfFailure(); if (BitConverter.ToUInt32(decBuffer, 0) == Pk21Magic) { diff --git a/src/hactoolnet/ProcessBench.cs b/src/hactoolnet/ProcessBench.cs index b68776a2..185006a4 100644 --- a/src/hactoolnet/ProcessBench.cs +++ b/src/hactoolnet/ProcessBench.cs @@ -25,7 +25,9 @@ namespace hactoolnet encryptWatch.Stop(); logger.SetTotal(0); - string rate = Util.GetBytesReadable((long)(src.GetSize() * iterations / encryptWatch.Elapsed.TotalSeconds)); + src.GetSize(out long srcSize).ThrowIfFailure(); + + string rate = Util.GetBytesReadable((long)(srcSize * iterations / encryptWatch.Elapsed.TotalSeconds)); logger.LogMessage($"{label}{rate}/s"); } diff --git a/src/hactoolnet/ProcessDelta.cs b/src/hactoolnet/ProcessDelta.cs index e59666c4..d8c1c4b7 100644 --- a/src/hactoolnet/ProcessDelta.cs +++ b/src/hactoolnet/ProcessDelta.cs @@ -19,7 +19,7 @@ namespace hactoolnet { IStorage deltaStorage = deltaFile; Span magic = stackalloc byte[4]; - deltaFile.Read(magic, 0); + deltaFile.Read(0, magic).ThrowIfFailure(); if (MemoryMarshal.Read(magic) != Ndv0Magic) { @@ -51,7 +51,9 @@ namespace hactoolnet using (var outFile = new FileStream(ctx.Options.OutFile, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { IStorage patchedStorage = delta.GetPatchedStorage(); - patchedStorage.CopyToStream(outFile, patchedStorage.GetSize(), ctx.Logger); + patchedStorage.GetSize(out long patchedStorageSize).ThrowIfFailure(); + + patchedStorage.CopyToStream(outFile, patchedStorageSize, ctx.Logger); } } } diff --git a/src/hactoolnet/ProcessFsBuild.cs b/src/hactoolnet/ProcessFsBuild.cs index 5d0d06ab..05a969f2 100644 --- a/src/hactoolnet/ProcessFsBuild.cs +++ b/src/hactoolnet/ProcessFsBuild.cs @@ -17,13 +17,15 @@ namespace hactoolnet var localFs = new LocalFileSystem(ctx.Options.InFile); var builder = new RomFsBuilder(localFs); - IStorage romfs = builder.Build(); + IStorage romFs = builder.Build(); ctx.Logger.LogMessage($"Building RomFS as {ctx.Options.OutFile}"); + romFs.GetSize(out long romFsSize).ThrowIfFailure(); + using (var outFile = new FileStream(ctx.Options.OutFile, FileMode.Create, FileAccess.ReadWrite)) { - romfs.CopyToStream(outFile, romfs.GetSize(), ctx.Logger); + romFs.CopyToStream(outFile, romFsSize, ctx.Logger); } ctx.Logger.LogMessage($"Finished writing {ctx.Options.OutFile}"); @@ -48,9 +50,11 @@ namespace hactoolnet ctx.Logger.LogMessage($"Building Partition FS as {ctx.Options.OutFile}"); + partitionFs.GetSize(out long partitionFsSize).ThrowIfFailure(); + using (var outFile = new FileStream(ctx.Options.OutFile, FileMode.Create, FileAccess.ReadWrite)) { - partitionFs.CopyToStream(outFile, partitionFs.GetSize(), ctx.Logger); + partitionFs.CopyToStream(outFile, partitionFsSize, ctx.Logger); } ctx.Logger.LogMessage($"Finished writing {ctx.Options.OutFile}"); diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index f7b7f09d..da1caf58 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -109,9 +109,12 @@ namespace hactoolnet { long bytesToRead = 1024L * 1024 * 1024 * 5; IStorage storage = OpenStorageByType(NcaSectionType.Data); - var dest = new NullStorage(storage.GetSize()); - int iterations = (int)(bytesToRead / storage.GetSize()) + 1; + storage.GetSize(out long sectionSize).ThrowIfFailure(); + + var dest = new NullStorage(sectionSize); + + int iterations = (int)(bytesToRead / sectionSize) + 1; ctx.Logger.LogMessage(iterations.ToString()); ctx.Logger.StartNewStopWatch(); diff --git a/src/hactoolnet/ProcessPfs.cs b/src/hactoolnet/ProcessPfs.cs index d36c2fec..fbabfad7 100644 --- a/src/hactoolnet/ProcessPfs.cs +++ b/src/hactoolnet/ProcessPfs.cs @@ -89,11 +89,13 @@ namespace hactoolnet Assembly thisAssembly = Assembly.GetExecutingAssembly(); Stream cert = thisAssembly.GetManifestResourceStream("hactoolnet.CA00000003_XS00000020"); builder.AddFile($"{ticket.RightsId.ToHexString()}.cert", cert.AsIFile(OpenMode.Read)); - + using (var outStream = new FileStream(ctx.Options.NspOut, FileMode.Create, FileAccess.ReadWrite)) { IStorage builtPfs = builder.Build(PartitionFileSystemType.Standard); - builtPfs.CopyToStream(outStream, builtPfs.GetSize(), ctx.Logger); + builtPfs.GetSize(out long pfsSize).ThrowIfFailure(); + + builtPfs.CopyToStream(outStream, pfsSize, ctx.Logger); } } } diff --git a/src/hactoolnet/ProcessRomfs.cs b/src/hactoolnet/ProcessRomfs.cs index cf53df5a..ac16b8df 100644 --- a/src/hactoolnet/ProcessRomfs.cs +++ b/src/hactoolnet/ProcessRomfs.cs @@ -28,9 +28,11 @@ namespace hactoolnet if (ctx.Options.RomfsOut != null) { + romfsStorage.GetSize(out long romFsSize).ThrowIfFailure(); + using (var outFile = new FileStream(ctx.Options.RomfsOut, FileMode.Create, FileAccess.ReadWrite)) { - romfsStorage.CopyToStream(outFile, romfsStorage.GetSize(), ctx.Logger); + romfsStorage.CopyToStream(outFile, romFsSize, ctx.Logger); } } diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index c973401f..6be16758 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -64,9 +64,12 @@ namespace hactoolnet { using (IFile outFile = save.OpenFile(destFilename, OpenMode.ReadWrite)) { - if (inFile.GetSize() != outFile.GetSize()) + inFile.GetSize(out long inFileSize).ThrowIfFailure(); + outFile.GetSize(out long outFileSize).ThrowIfFailure(); + + if (inFileSize != outFileSize) { - outFile.SetSize(inFile.GetSize()); + outFile.SetSize(inFileSize).ThrowIfFailure(); } inFile.CopyTo(outFile, ctx.Logger); From 9e9fd19f6356b8ee233c6fbe6721be619edeb981 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 8 Sep 2019 14:28:42 -0500 Subject: [PATCH 12/46] Return Result from IFileSystem methods --- src/LibHac/Fs/AesXtsDirectory.cs | 4 +- src/LibHac/Fs/AesXtsFileSystem.cs | 145 ++++++---- src/LibHac/Fs/ConcatenationFile.cs | 20 +- src/LibHac/Fs/ConcatenationFileSystem.cs | 156 ++++++----- src/LibHac/Fs/DirectorySaveDataFileSystem.cs | 126 +++++---- src/LibHac/Fs/FileSystemExtensions.cs | 60 ++-- src/LibHac/Fs/IFileSystem.cs | 115 ++++---- src/LibHac/Fs/LayeredFileSystem.cs | 124 +++++---- src/LibHac/Fs/LocalFileSystem.cs | 242 ++++++++++------- src/LibHac/Fs/PartitionFileSystem.cs | 69 +++-- src/LibHac/Fs/PartitionFileSystemBuilder.cs | 8 +- src/LibHac/Fs/ReadOnlyFileSystem.cs | 81 +++--- src/LibHac/Fs/ResultFs.cs | 1 - src/LibHac/Fs/RomFs/RomFsBuilder.cs | 6 +- src/LibHac/Fs/RomFs/RomFsFileSystem.cs | 92 +++---- .../Fs/Save/HierarchicalSaveFileTable.cs | 12 +- src/LibHac/Fs/Save/SaveDataFileSystem.cs | 217 +++++---------- src/LibHac/Fs/Save/SaveDataFileSystemCore.cs | 118 +++++--- src/LibHac/Fs/SubdirectoryFileSystem.cs | 75 ++--- .../FsClient/Accessors/FileSystemAccessor.cs | 90 +++--- src/LibHac/FsClient/DirectoryHandle.cs | 2 +- src/LibHac/FsClient/FileHandle.cs | 2 +- .../FsClient/FileSystemClient.FileSystem.cs | 4 +- src/LibHac/FsClient/FileSystemManager.cs | 256 ++++++++++-------- src/LibHac/FsClient/FileSystemManagerUtils.cs | 91 ++++--- .../Creators/IHostFileSystemCreator.cs | 2 +- .../ITargetManagerFileSystemCreator.cs | 2 +- .../Creators/SubDirectoryFileSystemCreator.cs | 12 +- src/LibHac/FsService/Util.cs | 20 +- src/LibHac/SwitchFs.cs | 16 +- src/LibHac/Xci.cs | 4 +- src/hactoolnet/FsUtils.cs | 62 +++-- src/hactoolnet/ProcessDelta.cs | 4 +- src/hactoolnet/ProcessNca.cs | 4 +- src/hactoolnet/ProcessSave.cs | 10 +- 35 files changed, 1246 insertions(+), 1006 deletions(-) diff --git a/src/LibHac/Fs/AesXtsDirectory.cs b/src/LibHac/Fs/AesXtsDirectory.cs index d1b14e92..67106723 100644 --- a/src/LibHac/Fs/AesXtsDirectory.cs +++ b/src/LibHac/Fs/AesXtsDirectory.cs @@ -56,7 +56,9 @@ namespace LibHac.Fs { try { - using (IFile file = BaseFileSystem.OpenFile(path, OpenMode.Read)) + BaseFileSystem.OpenFile(out IFile file, path, OpenMode.Read).ThrowIfFailure(); + + using (file) { file.GetSize(out long fileSize).ThrowIfFailure(); diff --git a/src/LibHac/Fs/AesXtsFileSystem.cs b/src/LibHac/Fs/AesXtsFileSystem.cs index 545c556f..3078bd05 100644 --- a/src/LibHac/Fs/AesXtsFileSystem.cs +++ b/src/LibHac/Fs/AesXtsFileSystem.cs @@ -27,14 +27,14 @@ namespace LibHac.Fs BlockSize = blockSize; } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { - BaseFileSystem.CreateDirectory(path); + return BaseFileSystem.CreateDirectory(path); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { - CreateFile(path, size, options, new byte[0x20]); + return CreateFile(path, size, options, new byte[0x20]); } /// @@ -45,83 +45,109 @@ namespace LibHac.Fs /// Flags to control how the file is created. /// Should usually be /// The 256-bit key containing a 128-bit data key followed by a 128-bit tweak key. - public void CreateFile(string path, long size, CreateFileOptions options, byte[] key) + public Result CreateFile(string path, long size, CreateFileOptions options, byte[] key) { long containerSize = AesXtsFile.HeaderLength + Util.AlignUp(size, 0x10); BaseFileSystem.CreateFile(path, containerSize, options); var header = new AesXtsFileHeader(key, size, path, KekSource, ValidationKey); - using (IFile baseFile = BaseFileSystem.OpenFile(path, OpenMode.Write)) + Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write); + if (rc.IsFailure()) return rc; + + using (baseFile) { - baseFile.Write(0, header.ToBytes(false)).ThrowIfFailure(); + rc = baseFile.Write(0, header.ToBytes(false)); + if (rc.IsFailure()) return rc; } + + return Result.Success; } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { - BaseFileSystem.DeleteDirectory(path); + return BaseFileSystem.DeleteDirectory(path); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { - BaseFileSystem.DeleteDirectoryRecursively(path); + return BaseFileSystem.DeleteDirectoryRecursively(path); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { - BaseFileSystem.CleanDirectoryRecursively(path); + return BaseFileSystem.CleanDirectoryRecursively(path); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { - BaseFileSystem.DeleteFile(path); + return BaseFileSystem.DeleteFile(path); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + directory = default; path = PathTools.Normalize(path); - IDirectory baseDir = BaseFileSystem.OpenDirectory(path, mode); + Result rc = BaseFileSystem.OpenDirectory(out IDirectory baseDir, path, mode); + if (rc.IsFailure()) return rc; - var dir = new AesXtsDirectory(this, baseDir, mode); - return dir; + directory = new AesXtsDirectory(this, baseDir, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); - IFile baseFile = BaseFileSystem.OpenFile(path, mode | OpenMode.Read); - var file = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize); + Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, mode | OpenMode.Read); + if (rc.IsFailure()) return rc; - file.ToDispose.Add(baseFile); - return file; + var xtsFile = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize); + + xtsFile.ToDispose.Add(baseFile); + + file = xtsFile; + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - BaseFileSystem.RenameDirectory(srcPath, dstPath); + // todo: Return proper result codes + + // Official code procedure: + // Make sure all file headers can be decrypted + // Rename directory to the new path + // Reencrypt file headers with new path + // If no errors, return + // Reencrypt any modified file headers with the old path + // Rename directory to the old path + + Result rc = BaseFileSystem.RenameDirectory(oldPath, newPath); + if (rc.IsFailure()) return rc; try { - RenameDirectoryImpl(srcPath, dstPath, false); + RenameDirectoryImpl(oldPath, newPath, false); } catch (Exception) { - RenameDirectoryImpl(srcPath, dstPath, true); - BaseFileSystem.RenameDirectory(dstPath, srcPath); + RenameDirectoryImpl(oldPath, newPath, true); + BaseFileSystem.RenameDirectory(oldPath, newPath); throw; } + + return Result.Success; } private void RenameDirectoryImpl(string srcDir, string dstDir, bool doRollback) { - IDirectory dir = OpenDirectory(dstDir, OpenDirectoryMode.All); + OpenDirectory(out IDirectory dir, dstDir, OpenDirectoryMode.All); foreach (DirectoryEntry entry in dir.Read()) { @@ -151,56 +177,60 @@ namespace LibHac.Fs } } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - AesXtsFileHeader header = ReadXtsHeader(srcPath, srcPath); + // todo: Return proper result codes - BaseFileSystem.RenameFile(srcPath, dstPath); + AesXtsFileHeader header = ReadXtsHeader(oldPath, oldPath); + + BaseFileSystem.RenameFile(oldPath, newPath); try { - WriteXtsHeader(header, dstPath, dstPath); + WriteXtsHeader(header, newPath, newPath); } catch (Exception) { - BaseFileSystem.RenameFile(dstPath, srcPath); - WriteXtsHeader(header, srcPath, srcPath); + BaseFileSystem.RenameFile(newPath, oldPath); + WriteXtsHeader(header, oldPath, oldPath); throw; } + + return Result.Success; } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { - return BaseFileSystem.GetEntryType(path); + return BaseFileSystem.GetEntryType(out entryType, path); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - return BaseFileSystem.GetFileTimeStampRaw(path); + return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return BaseFileSystem.GetFreeSpaceSize(path); + return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return BaseFileSystem.GetTotalSpaceSize(path); + return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path); } - public void Commit() + public Result Commit() { - BaseFileSystem.Commit(); + return BaseFileSystem.Commit(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - BaseFileSystem.QueryEntry(outBuffer, inBuffer, path, queryId); + return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, path); } private AesXtsFileHeader ReadXtsHeader(string filePath, string keyPath) @@ -218,7 +248,12 @@ namespace LibHac.Fs Debug.Assert(PathTools.IsNormalized(filePath.AsSpan())); Debug.Assert(PathTools.IsNormalized(keyPath.AsSpan())); - using (IFile file = BaseFileSystem.OpenFile(filePath, OpenMode.Read)) + header = null; + + Result rc = BaseFileSystem.OpenFile(out IFile file, filePath, OpenMode.Read); + if (rc.IsFailure()) return false; + + using (file) { header = new AesXtsFileHeader(file); @@ -233,7 +268,9 @@ namespace LibHac.Fs header.EncryptHeader(keyPath, KekSource, ValidationKey); - using (IFile file = BaseFileSystem.OpenFile(filePath, OpenMode.ReadWrite)) + BaseFileSystem.OpenFile(out IFile file, filePath, OpenMode.ReadWrite); + + using (file) { file.Write(0, header.ToBytes(false), WriteOption.Flush).ThrowIfFailure(); } diff --git a/src/LibHac/Fs/ConcatenationFile.cs b/src/LibHac/Fs/ConcatenationFile.cs index b50c7594..ad6842a8 100644 --- a/src/LibHac/Fs/ConcatenationFile.cs +++ b/src/LibHac/Fs/ConcatenationFile.cs @@ -130,7 +130,8 @@ namespace LibHac.Fs public override Result SetSize(long size) { - GetSize(out long currentSize).ThrowIfFailure(); + Result rc = GetSize(out long currentSize); + if (rc.IsFailure()) return rc; if (currentSize == size) return Result.Success; @@ -142,7 +143,7 @@ namespace LibHac.Fs IFile currentLastSubFile = Sources[currentSubFileCount - 1]; long newSubFileSize = QuerySubFileSize(currentSubFileCount - 1, size, SubFileSize); - Result rc = currentLastSubFile.SetSize(newSubFileSize); + rc = currentLastSubFile.SetSize(newSubFileSize); if (rc.IsFailure()) return rc; for (int i = currentSubFileCount; i < newSubFileCount; i++) @@ -150,8 +151,13 @@ namespace LibHac.Fs string newSubFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i); newSubFileSize = QuerySubFileSize(i, size, SubFileSize); - BaseFileSystem.CreateFile(newSubFilePath, newSubFileSize, CreateFileOptions.None); - Sources.Add(BaseFileSystem.OpenFile(newSubFilePath, Mode)); + rc = BaseFileSystem.CreateFile(newSubFilePath, newSubFileSize, CreateFileOptions.None); + if (rc.IsFailure()) return rc; + + rc = BaseFileSystem.OpenFile(out IFile newSubFile, newSubFilePath, Mode); + if (rc.IsFailure()) return rc; + + Sources.Add(newSubFile); } } else @@ -162,12 +168,14 @@ namespace LibHac.Fs Sources.RemoveAt(i); string subFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i); - BaseFileSystem.DeleteFile(subFilePath); + + rc = BaseFileSystem.DeleteFile(subFilePath); + if (rc.IsFailure()) return rc; } long newLastFileSize = QuerySubFileSize(newSubFileCount - 1, size, SubFileSize); - Result rc = Sources[newSubFileCount - 1].SetSize(newLastFileSize); + rc = Sources[newSubFileCount - 1].SetSize(newLastFileSize); if (rc.IsFailure()) return rc; } diff --git a/src/LibHac/Fs/ConcatenationFileSystem.cs b/src/LibHac/Fs/ConcatenationFileSystem.cs index f9df0964..9c2a4471 100644 --- a/src/LibHac/Fs/ConcatenationFileSystem.cs +++ b/src/LibHac/Fs/ConcatenationFileSystem.cs @@ -68,11 +68,19 @@ namespace LibHac.Fs #if CROSS_PLATFORM private bool IsConcatenationFileHeuristic(string path) { - if (BaseFileSystem.GetEntryType(path) != DirectoryEntryType.Directory) return false; + // Check if the path is a directory + Result getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType pathType, path); + if (getTypeResult.IsFailure() || pathType != DirectoryEntryType.Directory) return false; - if (BaseFileSystem.GetEntryType(PathTools.Combine(path, "00")) != DirectoryEntryType.File) return false; + // Check if the directory contains at least one subfile + getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType subFileType, PathTools.Combine(path, "00")); + if (getTypeResult.IsFailure() || subFileType != DirectoryEntryType.File) return false; - if (BaseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directory).GetEntryCount() > 0) return false; + // Make sure the directory contains no subdirectories + Result rc = BaseFileSystem.OpenDirectory(out IDirectory dir, path, OpenDirectoryMode.Directory); + if (rc.IsFailure()) return false; + + if (dir.GetEntryCount() > 0) return false; // Should be enough checks to avoid most false positives. Maybe return true; @@ -91,21 +99,21 @@ namespace LibHac.Fs BaseFileSystem.SetFileAttributes(path, attributes); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { path = PathTools.Normalize(path); string parent = PathTools.GetParentDirectory(path); if (IsConcatenationFile(parent)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, - "Cannot create a directory inside of a concatenation file"); + // Cannot create a directory inside of a concatenation file + return ResultFs.PathNotFound.Log(); } - BaseFileSystem.CreateDirectory(path); + return BaseFileSystem.CreateDirectory(path); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); @@ -113,8 +121,7 @@ namespace LibHac.Fs if (!options.HasFlag(CreateFileOptions.CreateConcatenationFile)) { - BaseFileSystem.CreateFile(path, size, newOptions); - return; + return BaseFileSystem.CreateFile(path, size, newOptions); } // A concatenation file directory can't contain normal files @@ -122,11 +129,13 @@ namespace LibHac.Fs if (IsConcatenationFile(parentDir)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, - "Cannot create a concatenation file inside of a concatenation file"); + // Cannot create a file inside of a concatenation file + return ResultFs.PathNotFound.Log(); } - BaseFileSystem.CreateDirectory(path); + Result rc = BaseFileSystem.CreateDirectory(path); + if (rc.IsFailure()) return rc; + SetConcatenationFileAttribute(path); long remaining = size; @@ -136,82 +145,95 @@ namespace LibHac.Fs long fileSize = Math.Min(SubFileSize, remaining); string fileName = GetSubFilePath(path, i); - BaseFileSystem.CreateFile(fileName, fileSize, CreateFileOptions.None); + Result createSubFileResult = BaseFileSystem.CreateFile(fileName, fileSize, CreateFileOptions.None); + + if (createSubFileResult.IsFailure()) + { + BaseFileSystem.DeleteDirectoryRecursively(path); + return createSubFileResult; + } remaining -= fileSize; } + + return Result.Success; } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { path = PathTools.Normalize(path); if (IsConcatenationFile(path)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - BaseFileSystem.DeleteDirectory(path); + return BaseFileSystem.DeleteDirectory(path); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) ThrowHelper.ThrowResult(ResultFs.PathNotFound); + if (IsConcatenationFile(path)) return ResultFs.PathNotFound.Log(); - BaseFileSystem.DeleteDirectoryRecursively(path); + return BaseFileSystem.DeleteDirectoryRecursively(path); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) ThrowHelper.ThrowResult(ResultFs.PathNotFound); + if (IsConcatenationFile(path)) return ResultFs.PathNotFound.Log(); - BaseFileSystem.CleanDirectoryRecursively(path); + return BaseFileSystem.CleanDirectoryRecursively(path); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { path = PathTools.Normalize(path); if (!IsConcatenationFile(path)) { - BaseFileSystem.DeleteFile(path); + return BaseFileSystem.DeleteFile(path); } int count = GetSubFileCount(path); for (int i = 0; i < count; i++) { - BaseFileSystem.DeleteFile(GetSubFilePath(path, i)); + Result rc = BaseFileSystem.DeleteFile(GetSubFilePath(path, i)); + if (rc.IsFailure()) return rc; } - BaseFileSystem.DeleteDirectory(path); + return BaseFileSystem.DeleteDirectory(path); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + directory = default; path = PathTools.Normalize(path); if (IsConcatenationFile(path)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - IDirectory parentDir = BaseFileSystem.OpenDirectory(path, OpenDirectoryMode.All); - var dir = new ConcatenationDirectory(this, parentDir, mode); - return dir; + Result rc = BaseFileSystem.OpenDirectory(out IDirectory parentDir, path, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + directory = new ConcatenationDirectory(this, parentDir, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); if (!IsConcatenationFile(path)) { - return BaseFileSystem.OpenFile(path, mode); + return BaseFileSystem.OpenFile(out file, path, mode); } int fileCount = GetSubFileCount(path); @@ -221,75 +243,85 @@ namespace LibHac.Fs for (int i = 0; i < fileCount; i++) { string filePath = GetSubFilePath(path, i); - IFile file = BaseFileSystem.OpenFile(filePath, mode); - files.Add(file); + + Result rc = BaseFileSystem.OpenFile(out IFile subFile, filePath, mode); + if (rc.IsFailure()) return rc; + + files.Add(subFile); } - return new ConcatenationFile(BaseFileSystem, path, files, SubFileSize, mode); + file = new ConcatenationFile(BaseFileSystem, path, files, SubFileSize, mode); + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - if (IsConcatenationFile(srcPath)) + if (IsConcatenationFile(oldPath)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - BaseFileSystem.RenameDirectory(srcPath, dstPath); + return BaseFileSystem.RenameDirectory(oldPath, newPath); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - if (IsConcatenationFile(srcPath)) + if (IsConcatenationFile(oldPath)) { - BaseFileSystem.RenameDirectory(srcPath, dstPath); + return BaseFileSystem.RenameDirectory(oldPath, newPath); } else { - BaseFileSystem.RenameFile(srcPath, dstPath); + return BaseFileSystem.RenameFile(oldPath, newPath); } } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) return DirectoryEntryType.File; + if (IsConcatenationFile(path)) + { + entryType = DirectoryEntryType.File; + return Result.Success; + } - return BaseFileSystem.GetEntryType(path); + return BaseFileSystem.GetEntryType(out entryType, path); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return BaseFileSystem.GetFreeSpaceSize(path); + return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return BaseFileSystem.GetTotalSpaceSize(path); + return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - return BaseFileSystem.GetFileTimeStampRaw(path); + return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path); } - public void Commit() + public Result Commit() { - BaseFileSystem.Commit(); + return BaseFileSystem.Commit(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - if (queryId != QueryId.MakeConcatFile) ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInConcatFsQueryEntry); + if (queryId != QueryId.MakeConcatFile) return ResultFs.UnsupportedOperationInConcatFsQueryEntry.Log(); SetConcatenationFileAttribute(path); + + return Result.Success; } private int GetSubFileCount(string dirPath) diff --git a/src/LibHac/Fs/DirectorySaveDataFileSystem.cs b/src/LibHac/Fs/DirectorySaveDataFileSystem.cs index 3fe9f866..9e4aca7e 100644 --- a/src/LibHac/Fs/DirectorySaveDataFileSystem.cs +++ b/src/LibHac/Fs/DirectorySaveDataFileSystem.cs @@ -33,162 +33,170 @@ namespace LibHac.Fs } } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.CreateDirectory(fullPath); + return BaseFs.CreateDirectory(fullPath); } } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.CreateFile(fullPath, size, options); + return BaseFs.CreateFile(fullPath, size, options); } } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.DeleteDirectory(fullPath); + return BaseFs.DeleteDirectory(fullPath); } } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.DeleteDirectoryRecursively(fullPath); + return BaseFs.DeleteDirectoryRecursively(fullPath); } } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.CleanDirectoryRecursively(fullPath); + return BaseFs.CleanDirectoryRecursively(fullPath); } } - public void DeleteFile(string path) + public Result DeleteFile(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.DeleteFile(fullPath); + return BaseFs.DeleteFile(fullPath); } } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - return BaseFs.OpenDirectory(fullPath, mode); + return BaseFs.OpenDirectory(out directory, fullPath, mode); } } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - IFile baseFile = BaseFs.OpenFile(fullPath, mode); - var file = new DirectorySaveDataFile(this, baseFile); + Result rc = BaseFs.OpenFile(out IFile baseFile, fullPath, mode); + if (rc.IsFailure()) return rc; + + file = new DirectorySaveDataFile(this, baseFile); if (mode.HasFlag(OpenMode.Write)) { OpenWritableFileCount++; } - return file; + return Result.Success; } } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - string fullSrcPath = GetFullPath(PathTools.Normalize(srcPath)); - string fullDstPath = GetFullPath(PathTools.Normalize(dstPath)); + string fullOldPath = GetFullPath(PathTools.Normalize(oldPath)); + string fullNewPath = GetFullPath(PathTools.Normalize(newPath)); lock (Locker) { - BaseFs.RenameDirectory(fullSrcPath, fullDstPath); + return BaseFs.RenameDirectory(fullOldPath, fullNewPath); } } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - string fullSrcPath = GetFullPath(PathTools.Normalize(srcPath)); - string fullDstPath = GetFullPath(PathTools.Normalize(dstPath)); + string fullOldPath = GetFullPath(PathTools.Normalize(oldPath)); + string fullNewPath = GetFullPath(PathTools.Normalize(newPath)); lock (Locker) { - BaseFs.RenameFile(fullSrcPath, fullDstPath); + return BaseFs.RenameFile(fullOldPath, fullNewPath); } } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - return BaseFs.GetEntryType(fullPath); + return BaseFs.GetEntryType(out entryType, fullPath); } } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + freeSpace = default; + return ResultFs.NotImplemented.Log(); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + totalSpace = default; + return ResultFs.NotImplemented.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void Commit() + public Result Commit() { - if (OpenWritableFileCount > 0) + lock (Locker) { - ThrowHelper.ThrowResult(ResultFs.WritableFileOpen, - "All files must be closed before commiting save data."); + if (OpenWritableFileCount > 0) + { + // All files must be closed before commiting save data. + return ResultFs.WritableFileOpen.Log(); + } + + Result rc = SynchronizeDirectory(SyncDir, WorkingDir); + if (rc.IsFailure()) return rc; + + rc = BaseFs.DeleteDirectoryRecursively(CommittedDir); + if (rc.IsFailure()) return rc; + + return BaseFs.RenameDirectory(SyncDir, CommittedDir); } - - SynchronizeDirectory(SyncDir, WorkingDir); - - BaseFs.DeleteDirectoryRecursively(CommittedDir); - - BaseFs.RenameDirectory(SyncDir, CommittedDir); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); + return ResultFs.NotImplemented.Log(); } private string GetFullPath(string path) @@ -196,19 +204,21 @@ namespace LibHac.Fs return PathTools.Normalize(PathTools.Combine(WorkingDir, path)); } - private void SynchronizeDirectory(string dest, string src) + private Result SynchronizeDirectory(string dest, string src) { - if (BaseFs.DirectoryExists(dest)) - { - BaseFs.DeleteDirectoryRecursively(dest); - } + Result rc = BaseFs.DeleteDirectoryRecursively(dest); + if (rc.IsFailure() && rc != ResultFs.PathNotFound) return rc; - BaseFs.CreateDirectory(dest); + rc = BaseFs.CreateDirectory(dest); + if (rc.IsFailure()) return rc; - IDirectory sourceDir = BaseFs.OpenDirectory(src, OpenDirectoryMode.All); - IDirectory destDir = BaseFs.OpenDirectory(dest, OpenDirectoryMode.All); + rc = BaseFs.OpenDirectory(out IDirectory sourceDir, src, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; - sourceDir.CopyDirectory(destDir); + rc = BaseFs.OpenDirectory(out IDirectory destDir, dest, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + return sourceDir.CopyDirectory(destDir); } internal void NotifyCloseWritableFile() diff --git a/src/LibHac/Fs/FileSystemExtensions.cs b/src/LibHac/Fs/FileSystemExtensions.cs index 22643be6..50997c48 100644 --- a/src/LibHac/Fs/FileSystemExtensions.cs +++ b/src/LibHac/Fs/FileSystemExtensions.cs @@ -7,10 +7,11 @@ namespace LibHac.Fs { public static class FileSystemExtensions { - public static void CopyDirectory(this IDirectory source, IDirectory dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) + public static Result CopyDirectory(this IDirectory source, IDirectory dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) { IFileSystem sourceFs = source.ParentFileSystem; IFileSystem destFs = dest.ParentFileSystem; + Result rc; foreach (DirectoryEntry entry in source.Read()) { @@ -20,32 +21,47 @@ namespace LibHac.Fs if (entry.Type == DirectoryEntryType.Directory) { destFs.EnsureDirectoryExists(subDstPath); - IDirectory subSrcDir = sourceFs.OpenDirectory(subSrcPath, OpenDirectoryMode.All); - IDirectory subDstDir = destFs.OpenDirectory(subDstPath, OpenDirectoryMode.All); - subSrcDir.CopyDirectory(subDstDir, logger, options); + rc = sourceFs.OpenDirectory(out IDirectory subSrcDir, subSrcPath, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + rc = destFs.OpenDirectory(out IDirectory subDstDir, subDstPath, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + rc = subSrcDir.CopyDirectory(subDstDir, logger, options); + if (rc.IsFailure()) return rc; } if (entry.Type == DirectoryEntryType.File) { destFs.CreateOrOverwriteFile(subDstPath, entry.Size, options); - using (IFile srcFile = sourceFs.OpenFile(subSrcPath, OpenMode.Read)) - using (IFile dstFile = destFs.OpenFile(subDstPath, OpenMode.Write | OpenMode.AllowAppend)) + rc = sourceFs.OpenFile(out IFile srcFile, subSrcPath, OpenMode.Read); + if (rc.IsFailure()) return rc; + + using (srcFile) { - logger?.LogMessage(subSrcPath); - srcFile.CopyTo(dstFile, logger); + rc = destFs.OpenFile(out IFile dstFile, subDstPath, OpenMode.Write | OpenMode.AllowAppend); + if (rc.IsFailure()) return rc; + + using (dstFile) + { + logger?.LogMessage(subSrcPath); + srcFile.CopyTo(dstFile, logger); + } } } } + + return Result.Success; } public static void CopyFileSystem(this IFileSystem source, IFileSystem dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) { - IDirectory sourceRoot = source.OpenDirectory("/", OpenDirectoryMode.All); - IDirectory destRoot = dest.OpenDirectory("/", OpenDirectoryMode.All); + source.OpenDirectory(out IDirectory sourceRoot, "/", OpenDirectoryMode.All).ThrowIfFailure(); + dest.OpenDirectory(out IDirectory destRoot, "/", OpenDirectoryMode.All).ThrowIfFailure(); - sourceRoot.CopyDirectory(destRoot, logger, options); + sourceRoot.CopyDirectory(destRoot, logger, options).ThrowIfFailure(); } public static void Extract(this IFileSystem source, string destinationPath, IProgressReport logger = null) @@ -67,7 +83,9 @@ namespace LibHac.Fs public static IEnumerable EnumerateEntries(this IFileSystem fileSystem, string searchPattern, SearchOptions searchOptions) { - return fileSystem.OpenDirectory("/", OpenDirectoryMode.All).EnumerateEntries(searchPattern, searchOptions); + fileSystem.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.All).ThrowIfFailure(); + + return rootDir.EnumerateEntries(searchPattern, searchOptions); } public static IEnumerable EnumerateEntries(this IDirectory directory) @@ -91,7 +109,7 @@ namespace LibHac.Fs if (entry.Type != DirectoryEntryType.Directory || !recurse) continue; - IDirectory subDir = fs.OpenDirectory(PathTools.Combine(directory.FullPath, entry.Name), OpenDirectoryMode.All); + fs.OpenDirectory(out IDirectory subDir, PathTools.Combine(directory.FullPath, entry.Name), OpenDirectoryMode.All).ThrowIfFailure(); foreach (DirectoryEntry subEntry in subDir.EnumerateEntries(searchPattern, searchOptions)) { @@ -139,7 +157,9 @@ namespace LibHac.Fs public static int GetEntryCount(this IFileSystem fs, OpenDirectoryMode mode) { - return fs.OpenDirectory("/", OpenDirectoryMode.All).GetEntryCountRecursive(mode); + fs.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.All).ThrowIfFailure(); + + return rootDir.GetEntryCountRecursive(mode); } public static int GetEntryCountRecursive(this IDirectory directory, OpenDirectoryMode mode) @@ -171,7 +191,7 @@ namespace LibHac.Fs public static void SetConcatenationFileAttribute(this IFileSystem fs, string path) { - fs.QueryEntry(Span.Empty, Span.Empty, path, QueryId.MakeConcatFile); + fs.QueryEntry(Span.Empty, Span.Empty, QueryId.MakeConcatFile, path); } public static void CleanDirectoryRecursivelyGeneric(IDirectory directory) @@ -184,7 +204,7 @@ namespace LibHac.Fs if (entry.Type == DirectoryEntryType.Directory) { - IDirectory subDir = fs.OpenDirectory(subPath, OpenDirectoryMode.All); + fs.OpenDirectory(out IDirectory subDir, subPath, OpenDirectoryMode.All).ThrowIfFailure(); CleanDirectoryRecursivelyGeneric(subDir); fs.DeleteDirectory(subPath); @@ -208,12 +228,16 @@ namespace LibHac.Fs public static bool DirectoryExists(this IFileSystem fs, string path) { - return fs.GetEntryType(path) == DirectoryEntryType.Directory; + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + + return (rc.IsSuccess() && type == DirectoryEntryType.Directory); } public static bool FileExists(this IFileSystem fs, string path) { - return fs.GetEntryType(path) == DirectoryEntryType.File; + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + + return (rc.IsSuccess() && type == DirectoryEntryType.File); } public static void EnsureDirectoryExists(this IFileSystem fs, string path) diff --git a/src/LibHac/Fs/IFileSystem.cs b/src/LibHac/Fs/IFileSystem.cs index dc62fb24..0703baf9 100644 --- a/src/LibHac/Fs/IFileSystem.cs +++ b/src/LibHac/Fs/IFileSystem.cs @@ -11,14 +11,15 @@ namespace LibHac.Fs /// Creates all directories and subdirectories in the specified path unless they already exist. /// /// The full path of the directory to create. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The parent directory of the specified path does not exist: /// Specified path already exists as either a file or directory: /// Insufficient free space to create the directory: /// - void CreateDirectory(string path); + Result CreateDirectory(string path); /// /// Creates or overwrites a file at the specified path. @@ -27,162 +28,177 @@ namespace LibHac.Fs /// The initial size of the created file. /// Flags to control how the file is created. /// Should usually be + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The parent directory of the specified path does not exist: /// Specified path already exists as either a file or directory: /// Insufficient free space to create the file: /// - void CreateFile(string path, long size, CreateFileOptions options); + Result CreateFile(string path, long size, CreateFileOptions options); /// /// Deletes the specified directory. /// /// The full path of the directory to delete. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a file: /// The specified directory is not empty: /// - void DeleteDirectory(string path); + Result DeleteDirectory(string path); /// /// Deletes the specified directory and any subdirectories and files in the directory. /// /// The full path of the directory to delete. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a file: /// - void DeleteDirectoryRecursively(string path); + Result DeleteDirectoryRecursively(string path); /// /// Deletes any subdirectories and files in the specified directory. /// /// The full path of the directory to clean. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a file: /// - void CleanDirectoryRecursively(string path); + Result CleanDirectoryRecursively(string path); /// /// Deletes the specified file. /// /// The full path of the file to delete. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a directory: /// - void DeleteFile(string path); + Result DeleteFile(string path); /// /// Creates an instance for enumerating the specified directory. /// + /// If the operation returns successfully, + /// An instance for the specified directory. /// The directory's full path. /// Specifies which sub-entries should be enumerated. - /// An instance for the specified directory. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a file: /// - IDirectory OpenDirectory(string path, OpenDirectoryMode mode); + Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode); /// /// Opens an instance for the specified path. /// + /// If the operation returns successfully, + /// An instance for the specified path. /// The full path of the file to open. /// Specifies the access permissions of the created . - /// An instance for the specified path. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a directory: /// - IFile OpenFile(string path, OpenMode mode); + Result OpenFile(out IFile file, string path, OpenMode mode); /// /// Renames or moves a directory to a new location. /// - /// The full path of the directory to rename. - /// The new full path of the directory. - /// An instance for the specified path. + /// The full path of the directory to rename. + /// The new full path of the directory. + /// The of the requested operation. /// - /// If and are the same, this function does nothing and returns successfully. - /// A will be thrown with the given under the following conditions: + /// If and are the same, this function does nothing and returns . + /// The following codes may be returned under certain conditions: /// - /// does not exist or is a file: - /// 's parent directory does not exist: - /// already exists as either a file or directory: - /// Either or is a subpath of the other: + /// does not exist or is a file: + /// 's parent directory does not exist: + /// already exists as either a file or directory: + /// Either or is a subpath of the other: /// - void RenameDirectory(string srcPath, string dstPath); + Result RenameDirectory(string oldPath, string newPath); /// /// Renames or moves a file to a new location. /// - /// The full path of the file to rename. - /// The new full path of the file. + /// The full path of the file to rename. + /// The new full path of the file. + /// The of the requested operation. /// - /// If and are the same, this function does nothing and returns successfully. - /// A will be thrown with the given under the following conditions: + /// If and are the same, this function does nothing and returns successfully. + /// The following codes may be returned under certain conditions: /// - /// does not exist or is a directory: - /// 's parent directory does not exist: - /// already exists as either a file or directory: + /// does not exist or is a directory: + /// 's parent directory does not exist: + /// already exists as either a file or directory: /// - void RenameFile(string srcPath, string dstPath); + Result RenameFile(string oldPath, string newPath); /// /// Determines whether the specified path is a file or directory, or does not exist. /// + /// If the operation returns successfully, the of the file. /// The full path to check. - /// The of the file. + /// The of the requested operation. /// /// This function operates slightly differently than it does in Horizon OS. /// Instead of returning when an entry is missing, /// the function will return . /// - DirectoryEntryType GetEntryType(string path); + Result GetEntryType(out DirectoryEntryType entryType, string path); /// /// Gets the amount of available free space on a drive, in bytes. /// + /// If the operation returns successfully, the amount of free space available on the drive, in bytes. /// The path of the drive to query. Unused in almost all cases. - /// The amount of free space available on the drive, in bytes. - long GetFreeSpaceSize(string path); + /// The of the requested operation. + Result GetFreeSpaceSize(out long freeSpace, string path); /// /// Gets the total size of storage space on a drive, in bytes. /// + /// If the operation returns successfully, the total size of the drive, in bytes. /// The path of the drive to query. Unused in almost all cases. - /// The total size of the drive, in bytes. - long GetTotalSpaceSize(string path); + /// The of the requested operation. + Result GetTotalSpaceSize(out long totalSpace, string path); /// /// Gets the creation, last accessed, and last modified timestamps of a file or directory. /// + /// If the operation returns successfully, the timestamps for the specified file or directory. + /// These value are expressed as Unix timestamps. /// The path of the file or directory. - /// The timestamps for the specified file or directory. - /// This value is expressed as a Unix timestamp + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist: /// - FileTimeStampRaw GetFileTimeStampRaw(string path); + Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path); /// /// Commits any changes to a transactional file system. /// Does nothing if called on a non-transactional file system. /// - void Commit(); + /// The of the requested operation. + Result Commit(); /// /// Performs a query on the specified file. @@ -193,9 +209,10 @@ namespace LibHac.Fs /// May be unused depending on the query type. /// The buffer for sending data to the query operation. /// May be unused depending on the query type. - /// The full path of the file to query. /// The type of query to perform. - void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId); + /// The full path of the file to query. + /// The of the requested operation. + Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path); } /// diff --git a/src/LibHac/Fs/LayeredFileSystem.cs b/src/LibHac/Fs/LayeredFileSystem.cs index d0e23930..500dde46 100644 --- a/src/LibHac/Fs/LayeredFileSystem.cs +++ b/src/LibHac/Fs/LayeredFileSystem.cs @@ -12,122 +12,138 @@ namespace LibHac.Fs Sources.AddRange(sourceFileSystems); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + directory = default; path = PathTools.Normalize(path); var dirs = new List(); foreach (IFileSystem fs in Sources) { - DirectoryEntryType type = fs.GetEntryType(path); + Result rc = fs.GetEntryType(out DirectoryEntryType entryType, path); + if (rc.IsFailure()) return rc; - if (type == DirectoryEntryType.File && dirs.Count == 0) + if (entryType == DirectoryEntryType.File && dirs.Count == 0) { ThrowHelper.ThrowResult(ResultFs.PathNotFound); } - if (fs.GetEntryType(path) == DirectoryEntryType.Directory) + if (entryType == DirectoryEntryType.Directory) { - dirs.Add(fs.OpenDirectory(path, mode)); + rc = fs.OpenDirectory(out IDirectory subDirectory, path, mode); + if (rc.IsFailure()) return rc; + + dirs.Add(subDirectory); } } - var dir = new LayeredFileSystemDirectory(this, dirs, path, mode); - - return dir; + directory = new LayeredFileSystemDirectory(this, dirs, path, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); foreach (IFileSystem fs in Sources) { - DirectoryEntryType type = fs.GetEntryType(path); + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + if (rc.IsFailure()) return rc; if (type == DirectoryEntryType.File) { - return fs.OpenFile(path, mode); + return fs.OpenFile(out file, path, mode); } if (type == DirectoryEntryType.Directory) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } } - ThrowHelper.ThrowResult(ResultFs.PathNotFound); - return default; + return ResultFs.PathNotFound.Log(); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); foreach (IFileSystem fs in Sources) { - DirectoryEntryType type = fs.GetEntryType(path); + Result getEntryResult = fs.GetEntryType(out DirectoryEntryType type, path); - if (type != DirectoryEntryType.NotFound) return type; - } - - return DirectoryEntryType.NotFound; - } - - public FileTimeStampRaw GetFileTimeStampRaw(string path) - { - path = PathTools.Normalize(path); - - foreach (IFileSystem fs in Sources) - { - if (fs.GetEntryType(path) != DirectoryEntryType.NotFound) + if (getEntryResult.IsSuccess() && type != DirectoryEntryType.NotFound) { - return fs.GetFileTimeStampRaw(path); + entryType = type; + return Result.Success; } } - ThrowHelper.ThrowResult(ResultFs.PathNotFound); - return default; + entryType = DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { path = PathTools.Normalize(path); foreach (IFileSystem fs in Sources) { - if (fs.GetEntryType(path) != DirectoryEntryType.NotFound) + Result getEntryResult = fs.GetEntryType(out DirectoryEntryType type, path); + + if (getEntryResult.IsSuccess() && type != DirectoryEntryType.NotFound) { - fs.QueryEntry(outBuffer, inBuffer, path, queryId); - return; + return fs.GetFileTimeStampRaw(out timeStamp, path); } } - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + timeStamp = default; + return ResultFs.PathNotFound.Log(); } - public void Commit() { } - - public void CreateDirectory(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void CreateFile(string path, long size, CreateFileOptions options) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void DeleteDirectory(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void DeleteDirectoryRecursively(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void CleanDirectoryRecursively(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void DeleteFile(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void RenameDirectory(string srcPath, string dstPath) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void RenameFile(string srcPath, string dstPath) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - - public long GetFreeSpaceSize(string path) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - return default; + path = PathTools.Normalize(path); + + foreach (IFileSystem fs in Sources) + { + Result getEntryResult = fs.GetEntryType(out DirectoryEntryType type, path); + + if (getEntryResult.IsSuccess() && type != DirectoryEntryType.NotFound) + { + return fs.QueryEntry(outBuffer, inBuffer, queryId, path); + } + } + + return ResultFs.PathNotFound.Log(); } - public long GetTotalSpaceSize(string path) + public Result Commit() { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - return default; + return Result.Success; + } + + public Result CreateDirectory(string path) => ResultFs.UnsupportedOperation.Log(); + public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperation.Log(); + public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperation.Log(); + public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperation.Log(); + public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperation.Log(); + public Result DeleteFile(string path) => ResultFs.UnsupportedOperation.Log(); + public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); + public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); + + public Result GetFreeSpaceSize(out long freeSpace, string path) + { + freeSpace = default; + return ResultFs.UnsupportedOperation.Log(); + } + + public Result GetTotalSpaceSize(out long totalSpace, string path) + { + totalSpace = default; + return ResultFs.UnsupportedOperation.Log(); } } } diff --git a/src/LibHac/Fs/LocalFileSystem.cs b/src/LibHac/Fs/LocalFileSystem.cs index 048e5c71..33c4b28b 100644 --- a/src/LibHac/Fs/LocalFileSystem.cs +++ b/src/LibHac/Fs/LocalFileSystem.cs @@ -58,7 +58,7 @@ namespace LibHac.Fs return GetSizeInternal(info); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); @@ -66,18 +66,18 @@ namespace LibHac.Fs if (dir.Exists) { - ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists); + return ResultFs.PathAlreadyExists.Log(); } if (dir.Parent?.Exists != true) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - CreateDirInternal(dir); + return CreateDirInternal(dir); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); @@ -85,121 +85,140 @@ namespace LibHac.Fs if (file.Exists) { - ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists); + return ResultFs.PathAlreadyExists.Log(); } if (file.Directory?.Exists != true) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - using (FileStream stream = CreateFileInternal(file)) + Result rc = CreateFileInternal(out FileStream stream, file); + + using (stream) { - SetStreamLengthInternal(stream, size); + if (rc.IsFailure()) return rc; + + return SetStreamLengthInternal(stream, size); } } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); DirectoryInfo dir = GetDirInfo(localPath); - DeleteDirectoryInternal(dir, false); + return DeleteDirectoryInternal(dir, false); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); DirectoryInfo dir = GetDirInfo(localPath); - DeleteDirectoryInternal(dir, true); + return DeleteDirectoryInternal(dir, true); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); foreach (string file in Directory.EnumerateFiles(localPath)) { - DeleteFileInternal(GetFileInfo(file)); + Result rc = DeleteFileInternal(GetFileInfo(file)); + if (rc.IsFailure()) return rc; } foreach (string dir in Directory.EnumerateDirectories(localPath)) { - DeleteDirectoryInternal(GetDirInfo(dir), true); + Result rc = DeleteDirectoryInternal(GetDirInfo(dir), true); + if (rc.IsFailure()) return rc; } + + return Result.Success; } - public void DeleteFile(string path) + public Result DeleteFile(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); FileInfo file = GetFileInfo(localPath); - DeleteFileInternal(file); + return DeleteFileInternal(file); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + // Getting the local path is done in the LocalDirectory constructor path = PathTools.Normalize(path); + directory = default; - if (GetEntryType(path) == DirectoryEntryType.File) + Result rc = GetEntryType(out DirectoryEntryType entryType, path); + if (rc.IsFailure()) return rc; + + if (entryType == DirectoryEntryType.File) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - return new LocalDirectory(this, path, mode); + directory = new LocalDirectory(this, path, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; string localPath = ResolveLocalPath(PathTools.Normalize(path)); - if (GetEntryType(path) == DirectoryEntryType.Directory) + Result rc = GetEntryType(out DirectoryEntryType entryType, path); + if (rc.IsFailure()) return rc; + + if (entryType == DirectoryEntryType.Directory) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - return new LocalFile(localPath, mode); + file = new LocalFile(localPath, mode); + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); // Official FS behavior is to do nothing in this case - if (srcPath == dstPath) return; + if (oldPath == newPath) return Result.Success; // FS does the subpath check before verifying the path exists - if (PathTools.IsSubPath(srcPath.AsSpan(), dstPath.AsSpan())) + if (PathTools.IsSubPath(oldPath.AsSpan(), newPath.AsSpan())) { ThrowHelper.ThrowResult(ResultFs.DestinationIsSubPathOfSource); } - DirectoryInfo srcDir = GetDirInfo(ResolveLocalPath(srcPath)); - DirectoryInfo dstDir = GetDirInfo(ResolveLocalPath(dstPath)); + DirectoryInfo srcDir = GetDirInfo(ResolveLocalPath(oldPath)); + DirectoryInfo dstDir = GetDirInfo(ResolveLocalPath(newPath)); - RenameDirInternal(srcDir, dstDir); + return RenameDirInternal(srcDir, dstDir); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - string srcLocalPath = ResolveLocalPath(PathTools.Normalize(srcPath)); - string dstLocalPath = ResolveLocalPath(PathTools.Normalize(dstPath)); + string srcLocalPath = ResolveLocalPath(PathTools.Normalize(oldPath)); + string dstLocalPath = ResolveLocalPath(PathTools.Normalize(newPath)); // Official FS behavior is to do nothing in this case - if (srcLocalPath == dstLocalPath) return; + if (srcLocalPath == dstLocalPath) return Result.Success; FileInfo srcFile = GetFileInfo(srcLocalPath); FileInfo dstFile = GetFileInfo(dstLocalPath); - RenameFileInternal(srcFile, dstFile); + return RenameFileInternal(srcFile, dstFile); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); @@ -207,48 +226,57 @@ namespace LibHac.Fs if (dir.Exists) { - return DirectoryEntryType.Directory; + entryType = DirectoryEntryType.Directory; + return Result.Success; } FileInfo file = GetFileInfo(localPath); if (file.Exists) { - return DirectoryEntryType.File; + entryType = DirectoryEntryType.File; + return Result.Success; } - return DirectoryEntryType.NotFound; + entryType = DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { + timeStamp = default; string localPath = ResolveLocalPath(PathTools.Normalize(path)); - if (!GetFileInfo(localPath).Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); - - FileTimeStampRaw timeStamp = default; + if (!GetFileInfo(localPath).Exists) return ResultFs.PathNotFound.Log(); timeStamp.Created = new DateTimeOffset(File.GetCreationTime(localPath)).ToUnixTimeSeconds(); timeStamp.Accessed = new DateTimeOffset(File.GetLastAccessTime(localPath)).ToUnixTimeSeconds(); timeStamp.Modified = new DateTimeOffset(File.GetLastWriteTime(localPath)).ToUnixTimeSeconds(); - return timeStamp; + return Result.Success; } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return new DriveInfo(BasePath).AvailableFreeSpace; + freeSpace = new DriveInfo(BasePath).AvailableFreeSpace; + return Result.Success; } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return new DriveInfo(BasePath).TotalSize; + totalSpace = new DriveInfo(BasePath).TotalSize; + return Result.Success; } - public void Commit() { } + public Result Commit() + { + return Result.Success; + } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + { + return ResultFs.UnsupportedOperation.Log(); + } private static long GetSizeInternal(FileInfo file) { @@ -268,35 +296,36 @@ namespace LibHac.Fs } } - private static FileStream CreateFileInternal(FileInfo file) + private static Result CreateFileInternal(out FileStream file, FileInfo fileInfo) { + file = default; + try { - return new FileStream(file.FullName, FileMode.CreateNew, FileAccess.ReadWrite); + file = new FileStream(fileInfo.FullName, FileMode.CreateNew, FileAccess.ReadWrite); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) { - ThrowHelper.ThrowResult(ResultFs.InsufficientFreeSpace, ex); - throw; + return ResultFs.InsufficientFreeSpace.Log(); } catch (IOException ex) when (ex.HResult == ErrorFileExists) { - ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists, ex); - throw; + return ResultFs.PathAlreadyExists.Log(); } catch (Exception ex) when (ex is SecurityException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } + + return Result.Success; } - private static void SetStreamLengthInternal(Stream stream, long size) + private static Result SetStreamLengthInternal(Stream stream, long size) { try { @@ -304,128 +333,131 @@ namespace LibHac.Fs } catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) { - ThrowHelper.ThrowResult(ResultFs.InsufficientFreeSpace, ex); - throw; + return ResultFs.InsufficientFreeSpace.Log(); } + + return Result.Success; } - private static void DeleteDirectoryInternal(DirectoryInfo dir, bool recursive) + private static Result DeleteDirectoryInternal(DirectoryInfo dir, bool recursive) { - if (!dir.Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); + if (!dir.Exists) return ResultFs.PathNotFound.Log(); try { dir.Delete(recursive); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (IOException ex) when (ex.HResult == ErrorDirNotEmpty) { - ThrowHelper.ThrowResult(ResultFs.DirectoryNotEmpty, ex); - throw; + return ResultFs.DirectoryNotEmpty.Log(); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } EnsureDeleted(dir); + + return Result.Success; } - private static void DeleteFileInternal(FileInfo file) + private static Result DeleteFileInternal(FileInfo file) { - if (!file.Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); + if (!file.Exists) return ResultFs.PathNotFound.Log(); try { file.Delete(); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (IOException ex) when (ex.HResult == ErrorDirNotEmpty) { - ThrowHelper.ThrowResult(ResultFs.DirectoryNotEmpty, ex); - throw; + return ResultFs.DirectoryNotEmpty.Log(); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } EnsureDeleted(file); + + return Result.Success; } - private static void CreateDirInternal(DirectoryInfo dir) + private static Result CreateDirInternal(DirectoryInfo dir) { try { dir.Create(); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) { - ThrowHelper.ThrowResult(ResultFs.InsufficientFreeSpace, ex); - throw; + return ResultFs.InsufficientFreeSpace.Log(); } catch (Exception ex) when (ex is SecurityException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } + + return Result.Success; } - private static void RenameDirInternal(DirectoryInfo source, DirectoryInfo dest) + private static Result RenameDirInternal(DirectoryInfo source, DirectoryInfo dest) { - if (!source.Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); - if (dest.Exists) ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists); + if (!source.Exists) return ResultFs.PathNotFound.Log(); + if (dest.Exists) return ResultFs.PathAlreadyExists.Log(); try { source.MoveTo(dest.FullName); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } + + return Result.Success; } - private static void RenameFileInternal(FileInfo source, FileInfo dest) + private static Result RenameFileInternal(FileInfo source, FileInfo dest) { - if (!source.Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); - if (dest.Exists) ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists); + if (!source.Exists) return ResultFs.PathNotFound.Log(); + if (dest.Exists) return ResultFs.PathAlreadyExists.Log(); try { source.MoveTo(dest.FullName); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } + + return Result.Success; } diff --git a/src/LibHac/Fs/PartitionFileSystem.cs b/src/LibHac/Fs/PartitionFileSystem.cs index e8d75888..a8ba92d4 100644 --- a/src/LibHac/Fs/PartitionFileSystem.cs +++ b/src/LibHac/Fs/PartitionFileSystem.cs @@ -29,12 +29,13 @@ namespace LibHac.Fs BaseStorage = storage; } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { - return new PartitionDirectory(this, path, mode); + directory = new PartitionDirectory(this, path, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { path = PathTools.Normalize(path).TrimStart('/'); @@ -43,7 +44,8 @@ namespace LibHac.Fs ThrowHelper.ThrowResult(ResultFs.PathNotFound); } - return OpenFile(entry, mode); + file = OpenFile(entry, mode); + return Result.Success; } public IFile OpenFile(PartitionFileEntry entry, OpenMode mode) @@ -51,46 +53,59 @@ namespace LibHac.Fs return new PartitionFile(BaseStorage, HeaderSize + entry.Offset, entry.Size, mode); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { + entryType = DirectoryEntryType.NotFound; path = PathTools.Normalize(path); - if (path == "/") return DirectoryEntryType.Directory; + if (path == "/") + { + entryType = DirectoryEntryType.Directory; + return Result.Success; + } - if (FileDict.ContainsKey(path.TrimStart('/'))) return DirectoryEntryType.File; + if (FileDict.ContainsKey(path.TrimStart('/'))) + { + entryType = DirectoryEntryType.File; + return Result.Success; + } - return DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public void CreateDirectory(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void CreateFile(string path, long size, CreateFileOptions options) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void DeleteDirectory(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void DeleteDirectoryRecursively(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void CleanDirectoryRecursively(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void DeleteFile(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void RenameDirectory(string srcPath, string dstPath) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void RenameFile(string srcPath, string dstPath) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); + public Result CreateDirectory(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result DeleteFile(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + freeSpace = default; + return ResultFs.NotImplemented.Log(); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + totalSpace = default; + return ResultFs.NotImplemented.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void Commit() { } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => ThrowHelper.ThrowResult(ResultFs.NotImplemented); + public Result Commit() + { + return Result.Success; + } + + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) => ResultFs.NotImplemented.Log(); } public enum PartitionFileSystemType diff --git a/src/LibHac/Fs/PartitionFileSystemBuilder.cs b/src/LibHac/Fs/PartitionFileSystemBuilder.cs index d997dd0f..9a41c18d 100644 --- a/src/LibHac/Fs/PartitionFileSystemBuilder.cs +++ b/src/LibHac/Fs/PartitionFileSystemBuilder.cs @@ -22,11 +22,13 @@ namespace LibHac.Fs /// public PartitionFileSystemBuilder(IFileSystem input) { - IDirectory rootDir = input.OpenDirectory("/", OpenDirectoryMode.File); + input.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.File).ThrowIfFailure(); - foreach (DirectoryEntry file in rootDir.Read().OrderBy(x => x.FullPath, StringComparer.Ordinal)) + foreach (DirectoryEntry entry in rootDir.Read().OrderBy(x => x.FullPath, StringComparer.Ordinal)) { - AddFile(file.FullPath.TrimStart('/'), input.OpenFile(file.FullPath, OpenMode.Read)); + input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure(); + + AddFile(entry.FullPath.TrimStart('/'), file); } } diff --git a/src/LibHac/Fs/ReadOnlyFileSystem.cs b/src/LibHac/Fs/ReadOnlyFileSystem.cs index 43a9d8c3..417b2526 100644 --- a/src/LibHac/Fs/ReadOnlyFileSystem.cs +++ b/src/LibHac/Fs/ReadOnlyFileSystem.cs @@ -11,71 +11,82 @@ namespace LibHac.Fs BaseFs = baseFileSystem; } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { - IDirectory baseDir = BaseFs.OpenDirectory(path, mode); - return new ReadOnlyDirectory(this, baseDir); + directory = default; + + Result rc = BaseFs.OpenDirectory(out IDirectory baseDir, path, mode); + if (rc.IsFailure()) return rc; + + directory = new ReadOnlyDirectory(this, baseDir); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { - IFile baseFile = BaseFs.OpenFile(path, mode); - return new ReadOnlyFile(baseFile); + file = default; + + Result rc = BaseFs.OpenFile(out IFile baseFile, path, mode); + if (rc.IsFailure()) return rc; + + file = new ReadOnlyFile(baseFile); + return Result.Success; } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { - return BaseFs.GetEntryType(path); + return BaseFs.GetEntryType(out entryType, path); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return 0; + freeSpace = 0; + return Result.Success; + + // FS does: + // return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log(); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return BaseFs.GetTotalSpaceSize(path); + return BaseFs.GetTotalSpaceSize(out totalSpace, path); + + // FS does: + // return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - return BaseFs.GetFileTimeStampRaw(path); + return BaseFs.GetFileTimeStampRaw(out timeStamp, path); + + // FS does: + // return ResultFs.NotImplemented.Log(); } - public void Commit() + public Result Commit() { - + return Result.Success; } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - BaseFs.QueryEntry(outBuffer, inBuffer, path, queryId); + return ResultFs.NotImplemented.Log(); } - public void CreateDirectory(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result CreateDirectory(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void CreateFile(string path, long size, CreateFileOptions options) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void DeleteDirectory(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void DeleteDirectoryRecursively(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void CleanDirectoryRecursively(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void DeleteFile(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result DeleteFile(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void RenameDirectory(string srcPath, string dstPath) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); - - public void RenameFile(string srcPath, string dstPath) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); } } diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index a3733289..fcc8eb68 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -11,7 +11,6 @@ public static Result InsufficientFreeSpace => new Result(ModuleFs, 30); public static Result MountNameAlreadyExists => new Result(ModuleFs, 60); - public static Result ResultPartitionNotFound => new Result(ModuleFs, 1002); public static Result TargetNotFound => new Result(ModuleFs, 1002); public static Result NotImplemented => new Result(ModuleFs, 3001); diff --git a/src/LibHac/Fs/RomFs/RomFsBuilder.cs b/src/LibHac/Fs/RomFs/RomFsBuilder.cs index 8d067e6e..055e2c4f 100644 --- a/src/LibHac/Fs/RomFs/RomFsBuilder.cs +++ b/src/LibHac/Fs/RomFs/RomFsBuilder.cs @@ -32,10 +32,12 @@ namespace LibHac.Fs.RomFs /// public RomFsBuilder(IFileSystem input) { - foreach (DirectoryEntry file in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File) + foreach (DirectoryEntry entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File) .OrderBy(x => x.FullPath, StringComparer.Ordinal)) { - AddFile(file.FullPath, input.OpenFile(file.FullPath, OpenMode.Read)); + input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure(); + + AddFile(entry.FullPath, file); } } diff --git a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs index ee944186..0b9970a4 100644 --- a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs @@ -22,52 +22,63 @@ namespace LibHac.Fs.RomFs FileTable = new HierarchicalRomFileTable(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { + entryType = DirectoryEntryType.NotFound; path = PathTools.Normalize(path); if (FileTable.TryOpenFile(path, out RomFileInfo _)) { - return DirectoryEntryType.File; + entryType = DirectoryEntryType.File; + return Result.Success; } if (FileTable.TryOpenDirectory(path, out FindPosition _)) { - return DirectoryEntryType.Directory; + entryType = DirectoryEntryType.Directory; + return Result.Success; } - return DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public void Commit() { } - - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result Commit() { + return Result.Success; + } + + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + { + directory = default; path = PathTools.Normalize(path); if (!FileTable.TryOpenDirectory(path, out FindPosition position)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - return new RomFsDirectory(this, path, position, mode); + directory = new RomFsDirectory(this, path, position, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); if (!FileTable.TryOpenFile(path, out RomFileInfo info)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } if (mode != OpenMode.Read) { - ThrowHelper.ThrowResult(ResultFs.InvalidArgument, "RomFs files must be opened read-only."); + // RomFs files must be opened read-only. + return ResultFs.InvalidArgument.Log(); } - return new RomFsFile(BaseStorage, Header.DataOffset + info.Offset, info.Length); + file = new RomFsFile(BaseStorage, Header.DataOffset + info.Offset, info.Length); + return Result.Success; } public IStorage GetBaseStorage() @@ -75,50 +86,37 @@ namespace LibHac.Fs.RomFs return BaseStorage; } - public void CreateDirectory(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); + public Result CreateDirectory(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result DeleteFile(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public void CreateFile(string path, long size, CreateFileOptions options) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void DeleteDirectory(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void DeleteDirectoryRecursively(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void CleanDirectoryRecursively(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void DeleteFile(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void RenameDirectory(string srcPath, string dstPath) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void RenameFile(string srcPath, string dstPath) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationRomFsFileSystemGetSpace); - return default; + freeSpace = default; + return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log(); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationRomFsFileSystemGetSpace); - return default; + totalSpace = default; + return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => - ThrowHelper.ThrowResult(ResultFs.NotImplemented); + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + { + return ResultFs.NotImplemented.Log(); + } } public class RomfsHeader diff --git a/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs b/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs index 07b8ac5e..78555ee3 100644 --- a/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs +++ b/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs @@ -338,11 +338,11 @@ namespace LibHac.Fs.Save FileTable.ChangeKey(ref oldKey, ref newKey); } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string srcPath, string dstPath) { if (srcPath == dstPath || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _)) { - throw new IOException(Messages.DestPathAlreadyExists); + return ResultFs.PathAlreadyExists.Log(); } ReadOnlySpan oldPathBytes = Util.GetUtf8Bytes(srcPath); @@ -350,19 +350,19 @@ namespace LibHac.Fs.Save if (!FindPathRecursive(oldPathBytes, out SaveEntryKey oldKey)) { - throw new DirectoryNotFoundException(); + return ResultFs.PathNotFound.Log(); } int dirIndex = DirectoryTable.GetIndexFromKey(ref oldKey).Index; if (!FindPathRecursive(newPathBytes, out SaveEntryKey newKey)) { - throw new IOException(Messages.PartialPathNotFound); + return ResultFs.PathNotFound.Log(); } if (PathTools.IsSubPath(oldPathBytes, newPathBytes)) { - ThrowHelper.ThrowResult(ResultFs.DestinationIsSubPathOfSource); + return ResultFs.DestinationIsSubPathOfSource.Log(); } if (oldKey.Parent != newKey.Parent) @@ -372,6 +372,8 @@ namespace LibHac.Fs.Save } DirectoryTable.ChangeKey(ref oldKey, ref newKey); + + return Result.Success; } public bool TryOpenDirectory(string path, out SaveFindPosition position) diff --git a/src/LibHac/Fs/Save/SaveDataFileSystem.cs b/src/LibHac/Fs/Save/SaveDataFileSystem.cs index 8191ccba..e71d1a0c 100644 --- a/src/LibHac/Fs/Save/SaveDataFileSystem.cs +++ b/src/LibHac/Fs/Save/SaveDataFileSystem.cs @@ -142,198 +142,114 @@ namespace LibHac.Fs.Save IntegrityStorageType.Save, integrityCheckLevel, LeaveOpen); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { - try - { - SaveDataFileSystemCore.CreateDirectory(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.CreateDirectory(path); + + return SaveResults.ConvertToExternalResult(result); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { - try - { - SaveDataFileSystemCore.CreateFile(path, size, options); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.CreateFile(path, size, options); + + return SaveResults.ConvertToExternalResult(result); } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { - try - { - SaveDataFileSystemCore.DeleteDirectory(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.DeleteDirectory(path); + + return SaveResults.ConvertToExternalResult(result); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { - try - { - SaveDataFileSystemCore.DeleteDirectoryRecursively(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.DeleteDirectoryRecursively(path); + + return SaveResults.ConvertToExternalResult(result); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { - try - { - SaveDataFileSystemCore.CleanDirectoryRecursively(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.CleanDirectoryRecursively(path); + + return SaveResults.ConvertToExternalResult(result); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { - try - { - SaveDataFileSystemCore.DeleteFile(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.DeleteFile(path); + + return SaveResults.ConvertToExternalResult(result); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { - try - { - return SaveDataFileSystemCore.OpenDirectory(path, mode); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.OpenDirectory(out directory, path, mode); + + return SaveResults.ConvertToExternalResult(result); } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { - try - { - return SaveDataFileSystemCore.OpenFile(path, mode); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.OpenFile(out file, path, mode); + + return SaveResults.ConvertToExternalResult(result); } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - try - { - SaveDataFileSystemCore.RenameDirectory(srcPath, dstPath); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.RenameDirectory(oldPath, newPath); + + return SaveResults.ConvertToExternalResult(result); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - try - { - SaveDataFileSystemCore.RenameFile(srcPath, dstPath); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.RenameFile(oldPath, newPath); + + return SaveResults.ConvertToExternalResult(result); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { - try - { - return SaveDataFileSystemCore.GetEntryType(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.GetEntryType(out entryType, path); + + return SaveResults.ConvertToExternalResult(result); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - try - { - return SaveDataFileSystemCore.GetFreeSpaceSize(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.GetFreeSpaceSize(out freeSpace, path); + + return SaveResults.ConvertToExternalResult(result); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - try - { - return SaveDataFileSystemCore.GetTotalSpaceSize(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.GetTotalSpaceSize(out totalSpace, path); + + return SaveResults.ConvertToExternalResult(result); } - public void Commit() + public Result Commit() { - try - { - Commit(Keyset); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = Commit(Keyset); + + return SaveResults.ConvertToExternalResult(result); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => - ThrowHelper.ThrowResult(ResultFs.NotImplemented); + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) => + ResultFs.NotImplemented.Log(); - public bool Commit(Keyset keyset) + public Result Commit(Keyset keyset) { CoreDataIvfcStorage.Flush(); FatIvfcStorage?.Flush(); @@ -349,7 +265,7 @@ namespace LibHac.Fs.Save headerStream.Position = 0x108; headerStream.Write(hash, 0, hash.Length); - if (keyset == null || keyset.SaveMacKey.IsEmpty()) return false; + if (keyset == null || keyset.SaveMacKey.IsEmpty()) return ResultFs.PreconditionViolation; var cmacData = new byte[0x200]; var cmac = new byte[0x10]; @@ -363,7 +279,7 @@ namespace LibHac.Fs.Save headerStream.Write(cmac, 0, 0x10); headerStream.Flush(); - return true; + return Result.Success; } public void FsTrim() @@ -395,10 +311,5 @@ namespace LibHac.Fs.Save return journalValidity; } - - private void ConvertResultException(HorizonResultException ex) - { - ex.ResultValue = SaveResults.ConvertToExternalResult(ex.ResultValue); - } } } diff --git a/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs b/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs index a1fe5c3c..721fe75b 100644 --- a/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs +++ b/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs @@ -27,14 +27,16 @@ namespace LibHac.Fs.Save FileTable = new HierarchicalSaveFileTable(dirTableStorage, fileTableStorage); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { path = PathTools.Normalize(path); FileTable.AddDirectory(path); + + return Result.Success; } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); @@ -43,7 +45,7 @@ namespace LibHac.Fs.Save var emptyFileEntry = new SaveFileInfo { StartBlock = int.MinValue, Length = size }; FileTable.AddFile(path, ref emptyFileEntry); - return; + return Result.Success; } int blockCount = (int)Util.DivideByRoundUp(size, AllocationTable.Header.BlockSize); @@ -51,45 +53,56 @@ namespace LibHac.Fs.Save if (startBlock == -1) { - ThrowHelper.ThrowResult(ResultFs.AllocationTableInsufficientFreeBlocks, - "Not enough available space to create file."); + return ResultFs.AllocationTableInsufficientFreeBlocks.Log(); } var fileEntry = new SaveFileInfo { StartBlock = startBlock, Length = size }; FileTable.AddFile(path, ref fileEntry); + + return Result.Success; } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { path = PathTools.Normalize(path); FileTable.DeleteDirectory(path); + + return Result.Success; } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { path = PathTools.Normalize(path); - CleanDirectoryRecursively(path); + Result rc = CleanDirectoryRecursively(path); + if (rc.IsFailure()) return rc; + DeleteDirectory(path); + + return Result.Success; } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { path = PathTools.Normalize(path); - IDirectory dir = OpenDirectory(path, OpenDirectoryMode.All); + Result rc = OpenDirectory(out IDirectory dir, path, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + FileSystemExtensions.CleanDirectoryRecursivelyGeneric(dir); + + return Result.Success; } - public void DeleteFile(string path) + public Result DeleteFile(string path) { path = PathTools.Normalize(path); if (!FileTable.TryOpenFile(path, out SaveFileInfo fileInfo)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } if (fileInfo.StartBlock != int.MinValue) @@ -98,91 +111,110 @@ namespace LibHac.Fs.Save } FileTable.DeleteFile(path); + + return Result.Success; } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + directory = default; path = PathTools.Normalize(path); if (!FileTable.TryOpenDirectory(path, out SaveFindPosition position)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - return new SaveDataDirectory(this, path, position, mode); + directory = new SaveDataDirectory(this, path, position, mode); + + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); - if (!FileTable.TryOpenFile(path, out SaveFileInfo file)) + if (!FileTable.TryOpenFile(path, out SaveFileInfo fileInfo)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - AllocationTableStorage storage = OpenFatStorage(file.StartBlock); + AllocationTableStorage storage = OpenFatStorage(fileInfo.StartBlock); - return new SaveDataFile(storage, path, FileTable, file.Length, mode); + file = new SaveDataFile(storage, path, FileTable, fileInfo.Length, mode); + + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - FileTable.RenameDirectory(srcPath, dstPath); + return FileTable.RenameDirectory(oldPath, newPath); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - FileTable.RenameFile(srcPath, dstPath); + FileTable.RenameFile(oldPath, newPath); + + return Result.Success; } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); if (FileTable.TryOpenFile(path, out SaveFileInfo _)) { - return DirectoryEntryType.File; + entryType = DirectoryEntryType.File; + return Result.Success; } if (FileTable.TryOpenDirectory(path, out SaveFindPosition _)) { - return DirectoryEntryType.Directory; + entryType = DirectoryEntryType.Directory; + return Result.Success; } - return DirectoryEntryType.NotFound; + entryType = DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { int freeBlockCount = AllocationTable.GetFreeListLength(); - return Header.BlockSize * freeBlockCount; + freeSpace = Header.BlockSize * freeBlockCount; + + return Result.Success; } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return Header.BlockSize * Header.BlockCount; + totalSpace = Header.BlockSize * Header.BlockCount; + + return Result.Success; } - public void Commit() + public Result Commit() { - + return Result.Success; } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => - ThrowHelper.ThrowResult(ResultFs.NotImplemented); + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + { + return ResultFs.NotImplemented.Log(); + } public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); diff --git a/src/LibHac/Fs/SubdirectoryFileSystem.cs b/src/LibHac/Fs/SubdirectoryFileSystem.cs index db5f0ab5..57f80d1a 100644 --- a/src/LibHac/Fs/SubdirectoryFileSystem.cs +++ b/src/LibHac/Fs/SubdirectoryFileSystem.cs @@ -18,118 +18,119 @@ namespace LibHac.Fs RootPath = PathTools.Normalize(rootPath); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { path = PathTools.Normalize(path); - ParentFileSystem.CreateDirectory(ResolveFullPath(path)); + return ParentFileSystem.CreateDirectory(ResolveFullPath(path)); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); - ParentFileSystem.CreateFile(ResolveFullPath(path), size, options); + return ParentFileSystem.CreateFile(ResolveFullPath(path), size, options); } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { path = PathTools.Normalize(path); - ParentFileSystem.DeleteDirectory(ResolveFullPath(path)); + return ParentFileSystem.DeleteDirectory(ResolveFullPath(path)); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { path = PathTools.Normalize(path); - ParentFileSystem.DeleteDirectoryRecursively(ResolveFullPath(path)); + return ParentFileSystem.DeleteDirectoryRecursively(ResolveFullPath(path)); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { path = PathTools.Normalize(path); - ParentFileSystem.CleanDirectoryRecursively(ResolveFullPath(path)); + return ParentFileSystem.CleanDirectoryRecursively(ResolveFullPath(path)); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { path = PathTools.Normalize(path); - ParentFileSystem.DeleteFile(ResolveFullPath(path)); + return ParentFileSystem.DeleteFile(ResolveFullPath(path)); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { path = PathTools.Normalize(path); - IDirectory baseDir = ParentFileSystem.OpenDirectory(ResolveFullPath(path), mode); + ParentFileSystem.OpenDirectory(out IDirectory baseDir, ResolveFullPath(path), mode); - return new SubdirectoryFileSystemDirectory(this, baseDir, path, mode); + directory = new SubdirectoryFileSystemDirectory(this, baseDir, path, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { path = PathTools.Normalize(path); - return ParentFileSystem.OpenFile(ResolveFullPath(path), mode); + return ParentFileSystem.OpenFile(out file, ResolveFullPath(path), mode); } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - ParentFileSystem.RenameDirectory(ResolveFullPath(srcPath), ResolveFullPath(dstPath)); + return ParentFileSystem.RenameDirectory(oldPath, newPath); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - ParentFileSystem.RenameFile(ResolveFullPath(srcPath), ResolveFullPath(dstPath)); + return ParentFileSystem.RenameFile(oldPath, newPath); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); - return ParentFileSystem.GetEntryType(ResolveFullPath(path)); + return ParentFileSystem.GetEntryType(out entryType, ResolveFullPath(path)); } - public void Commit() + public Result Commit() { - ParentFileSystem.Commit(); + return ParentFileSystem.Commit(); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { path = PathTools.Normalize(path); - return ParentFileSystem.GetFreeSpaceSize(ResolveFullPath(path)); + return ParentFileSystem.GetFreeSpaceSize(out freeSpace, ResolveFullPath(path)); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { path = PathTools.Normalize(path); - return ParentFileSystem.GetTotalSpaceSize(ResolveFullPath(path)); + return ParentFileSystem.GetTotalSpaceSize(out totalSpace, ResolveFullPath(path)); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { path = PathTools.Normalize(path); - return ParentFileSystem.GetFileTimeStampRaw(ResolveFullPath(path)); + return ParentFileSystem.GetFileTimeStampRaw(out timeStamp, ResolveFullPath(path)); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { path = PathTools.Normalize(path); - ParentFileSystem.QueryEntry(outBuffer, inBuffer, ResolveFullPath(path), queryId); + return ParentFileSystem.QueryEntry(outBuffer, inBuffer, queryId, ResolveFullPath(path)); } } } diff --git a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs index 391f7381..317e7dd0 100644 --- a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs +++ b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs @@ -26,117 +26,125 @@ namespace LibHac.FsClient.Accessors FsManager = fsManager; } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { - FileSystem.CreateDirectory(path); + return FileSystem.CreateDirectory(path); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { - FileSystem.CreateFile(path, size, options); + return FileSystem.CreateFile(path, size, options); } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { - FileSystem.DeleteDirectory(path); + return FileSystem.DeleteDirectory(path); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { - FileSystem.DeleteDirectoryRecursively(path); + return FileSystem.DeleteDirectoryRecursively(path); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { - FileSystem.CleanDirectoryRecursively(path); + return FileSystem.CleanDirectoryRecursively(path); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { - FileSystem.DeleteFile(path); + return FileSystem.DeleteFile(path); } - public DirectoryAccessor OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out DirectoryAccessor directory, string path, OpenDirectoryMode mode) { - IDirectory dir = FileSystem.OpenDirectory(path, mode); + directory = default; - var accessor = new DirectoryAccessor(dir, this); + Result rc = FileSystem.OpenDirectory(out IDirectory rawDirectory, path, mode); + if (rc.IsFailure()) return rc; + + var accessor = new DirectoryAccessor(rawDirectory, this); lock (_locker) { OpenDirectories.Add(accessor); } - return accessor; + directory = accessor; + return Result.Success; } - public FileAccessor OpenFile(string path, OpenMode mode) + public Result OpenFile(out FileAccessor file, string path, OpenMode mode) { - IFile file = FileSystem.OpenFile(path, mode); + file = default; - var accessor = new FileAccessor(file, this, mode); + Result rc = FileSystem.OpenFile(out IFile rawFile, path, mode); + if (rc.IsFailure()) return rc; + + var accessor = new FileAccessor(rawFile, this, mode); lock (_locker) { OpenFiles.Add(accessor); } - return accessor; + file = accessor; + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - FileSystem.RenameDirectory(srcPath, dstPath); + return FileSystem.RenameDirectory(oldPath, newPath); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - FileSystem.RenameFile(srcPath, dstPath); + return FileSystem.RenameFile(oldPath, newPath); } - public void DirectoryExists(string path) + public bool DirectoryExists(string path) { - FileSystem.DirectoryExists(path); + return FileSystem.DirectoryExists(path); } - public void FileExists(string path) + public bool FileExists(string path) { - FileSystem.FileExists(path); + return FileSystem.FileExists(path); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType type, string path) { - return FileSystem.GetEntryType(path); + return FileSystem.GetEntryType(out type, path); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return FileSystem.GetFreeSpaceSize(path); + return FileSystem.GetFreeSpaceSize(out freeSpace, path); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return FileSystem.GetTotalSpaceSize(path); + return FileSystem.GetTotalSpaceSize(out totalSpace, path); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - return FileSystem.GetFileTimeStampRaw(path); + return FileSystem.GetFileTimeStampRaw(out timeStamp, path); } - public void Commit() + public Result Commit() { if (OpenFiles.Any(x => (x.OpenMode & OpenMode.Write) != 0)) { - ThrowHelper.ThrowResult(ResultFs.WritableFileOpen); + return ResultFs.WritableFileOpen.Log(); } - FileSystem.Commit(); + return FileSystem.Commit(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) { - FileSystem.QueryEntry(outBuffer, inBuffer, path, queryId); + return FileSystem.QueryEntry(outBuffer, inBuffer, queryId, path); } internal void NotifyCloseFile(FileAccessor file) diff --git a/src/LibHac/FsClient/DirectoryHandle.cs b/src/LibHac/FsClient/DirectoryHandle.cs index 9eb8cf2f..cab42040 100644 --- a/src/LibHac/FsClient/DirectoryHandle.cs +++ b/src/LibHac/FsClient/DirectoryHandle.cs @@ -12,7 +12,7 @@ namespace LibHac.FsClient Directory = directory; } - public int GetId() => Directory.GetHashCode(); + public int GetId() => Directory?.GetHashCode() ?? 0; public void Dispose() { diff --git a/src/LibHac/FsClient/FileHandle.cs b/src/LibHac/FsClient/FileHandle.cs index 387efe01..0c728291 100644 --- a/src/LibHac/FsClient/FileHandle.cs +++ b/src/LibHac/FsClient/FileHandle.cs @@ -12,7 +12,7 @@ namespace LibHac.FsClient File = file; } - public int GetId() => File.GetHashCode(); + public int GetId() => File?.GetHashCode() ?? 0; public void Dispose() { diff --git a/src/LibHac/FsClient/FileSystemClient.FileSystem.cs b/src/LibHac/FsClient/FileSystemClient.FileSystem.cs index f3676a12..ebd4ed12 100644 --- a/src/LibHac/FsClient/FileSystemClient.FileSystem.cs +++ b/src/LibHac/FsClient/FileSystemClient.FileSystem.cs @@ -55,12 +55,12 @@ namespace LibHac.FsClient throw new NotImplementedException(); } - public FileHandle OpenFile(out FileHandle handle, string path, OpenMode mode) + public Result OpenFile(out FileHandle handle, string path, OpenMode mode) { throw new NotImplementedException(); } - public DirectoryHandle OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) + public Result OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) { throw new NotImplementedException(); } diff --git a/src/LibHac/FsClient/FileSystemManager.cs b/src/LibHac/FsClient/FileSystemManager.cs index 10ca268f..7b4688bf 100644 --- a/src/LibHac/FsClient/FileSystemManager.cs +++ b/src/LibHac/FsClient/FileSystemManager.cs @@ -6,6 +6,7 @@ using LibHac.FsClient.Accessors; namespace LibHac.FsClient { + // Todo: Access log for FindFileSystem public class FileSystemManager { internal Horizon Os { get; } @@ -66,213 +67,229 @@ namespace LibHac.FsClient if (accessLog != null) AccessLog = accessLog; } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.CreateDirectory(subPath.ToString()); + rc = fileSystem.CreateDirectory(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.CreateDirectory(subPath.ToString()); + rc = fileSystem.CreateDirectory(subPath.ToString()); } + + return rc; } - public void CreateFile(string path, long size) + public Result CreateFile(string path, long size) { - CreateFile(path, size, CreateFileOptions.None); + return CreateFile(path, size, CreateFileOptions.None); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.CreateFile(subPath.ToString(), size, options); + rc = fileSystem.CreateFile(subPath.ToString(), size, options); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\", size: {size}"); } else { - fileSystem.CreateFile(subPath.ToString(), size, options); + rc = fileSystem.CreateFile(subPath.ToString(), size, options); } + + return rc; } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.DeleteDirectory(subPath.ToString()); + rc = fileSystem.DeleteDirectory(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.DeleteDirectory(subPath.ToString()); + rc = fileSystem.DeleteDirectory(subPath.ToString()); } + + return rc; } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.DeleteDirectoryRecursively(subPath.ToString()); + rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.DeleteDirectoryRecursively(subPath.ToString()); + rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); } + + return rc; } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.CleanDirectoryRecursively(subPath.ToString()); + rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.CleanDirectoryRecursively(subPath.ToString()); + rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); } + + return rc; } - public void DeleteFile(string path) + public Result DeleteFile(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.DeleteFile(subPath.ToString()); + rc = fileSystem.DeleteFile(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.DeleteFile(subPath.ToString()); + rc = fileSystem.DeleteFile(subPath.ToString()); } + + return rc; } - public void RenameDirectory(string oldPath, string newPath) + public Result RenameDirectory(string oldPath, string newPath) { - FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); + if (rc.IsFailure()) return rc; - FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath) - .ThrowIfFailure(); + rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); + if (rc.IsFailure()) return rc; if (oldFileSystem != newFileSystem) { - ThrowHelper.ThrowResult(ResultFs.DifferentDestFileSystem); + return ResultFs.DifferentDestFileSystem.Log(); } if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); } else { - oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); } + + return rc; } - public void RenameFile(string oldPath, string newPath) + public Result RenameFile(string oldPath, string newPath) { - FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); + if (rc.IsFailure()) return rc; - FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath) - .ThrowIfFailure(); + rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); + if (rc.IsFailure()) return rc; if (oldFileSystem != newFileSystem) { - ThrowHelper.ThrowResult(ResultFs.DifferentDestFileSystem); + return ResultFs.DifferentDestFileSystem.Log(); } if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); } else { - oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); } + + return rc; } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType type, string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + type = default; - DirectoryEntryType type; + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - type = fileSystem.GetEntryType(subPath.ToString()); + rc = fileSystem.GetEntryType(out type, subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - type = fileSystem.GetEntryType(subPath.ToString()); + rc = fileSystem.GetEntryType(out type, subPath.ToString()); } - return type; + return rc; } - public FileHandle OpenFile(string path, OpenMode mode) + public Result OpenFile(out FileHandle handle, string path, OpenMode mode) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + handle = default; - FileHandle handle; + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - FileAccessor file = fileSystem.OpenFile(subPath.ToString(), mode); + rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); handle = new FileHandle(file); TimeSpan endTime = Time.GetCurrent(); @@ -280,24 +297,24 @@ namespace LibHac.FsClient } else { - FileAccessor file = fileSystem.OpenFile(subPath.ToString(), mode); + rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); handle = new FileHandle(file); } - return handle; + return rc; } - public DirectoryHandle OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + handle = default; - DirectoryHandle handle; + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - DirectoryAccessor dir = fileSystem.OpenDirectory(subPath.ToString(), mode); + rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); handle = new DirectoryHandle(dir); TimeSpan endTime = Time.GetCurrent(); @@ -305,94 +322,105 @@ namespace LibHac.FsClient } else { - DirectoryAccessor dir = fileSystem.OpenDirectory(subPath.ToString(), mode); + rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); handle = new DirectoryHandle(dir); } - return handle; + return rc; } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + freeSpace = default; - return fileSystem.GetFreeSpaceSize(subPath.ToString()); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + return fileSystem.GetFreeSpaceSize(out freeSpace, subPath.ToString()); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + totalSpace = default; - return fileSystem.GetTotalSpaceSize(subPath.ToString()); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + return fileSystem.GetTotalSpaceSize(out totalSpace, subPath.ToString()); } - public FileTimeStampRaw GetFileTimeStamp(string path) + public Result GetFileTimeStamp(out FileTimeStampRaw timeStamp, string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + timeStamp = default; - return fileSystem.GetFileTimeStampRaw(subPath.ToString()); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + return fileSystem.GetFileTimeStampRaw(out timeStamp, subPath.ToString()); } - public void Commit(string mountName) + public Result Commit(string mountName) { - MountTable.Find(mountName, out FileSystemAccessor fileSystem).ThrowIfFailure(); + Result rc = MountTable.Find(mountName, out FileSystemAccessor fileSystem); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.Commit(); + rc = fileSystem.Commit(); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", name: \"{mountName}\""); } else { - fileSystem.Commit(); + rc = fileSystem.Commit(); } + + return rc; } // ========================== // Operations on file handles // ========================== - public int ReadFile(FileHandle handle, Span destination, long offset) + public Result ReadFile(out long bytesRead, FileHandle handle, Span destination, long offset) { - return ReadFile(handle, destination, offset, ReadOption.None); + return ReadFile(out bytesRead, handle, destination, offset, ReadOption.None); } - public int ReadFile(FileHandle handle, Span destination, long offset, ReadOption option) + public Result ReadFile(out long bytesRead, FileHandle handle, Span destination, long offset, ReadOption option) { - long bytesRead; + Result rc; if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.Read(out bytesRead, offset, destination, option).ThrowIfFailure(); + rc = handle.File.Read(out bytesRead, offset, destination, option); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, handle, $", offset: {offset}, size: {destination.Length}"); } else { - handle.File.Read(out bytesRead, offset, destination, option).ThrowIfFailure(); + rc = handle.File.Read(out bytesRead, offset, destination, option); } - return (int)bytesRead; + return rc; } - public void WriteFile(FileHandle handle, ReadOnlySpan source, long offset) + public Result WriteFile(FileHandle handle, ReadOnlySpan source, long offset) { - WriteFile(handle, source, offset, WriteOption.None); + return WriteFile(handle, source, offset, WriteOption.None); } - public void WriteFile(FileHandle handle, ReadOnlySpan source, long offset, WriteOption option) + public Result WriteFile(FileHandle handle, ReadOnlySpan source, long offset, WriteOption option) { + Result rc; + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.Write(offset, source, option); + rc = handle.File.Write(offset, source, option); TimeSpan endTime = Time.GetCurrent(); string optionString = (option & WriteOption.Flush) == 0 ? "" : $", write_option: {option}"; @@ -401,47 +429,55 @@ namespace LibHac.FsClient } else { - handle.File.Write(offset, source, option); + rc = handle.File.Write(offset, source, option); } + + return rc; } - public void FlushFile(FileHandle handle) + public Result FlushFile(FileHandle handle) { + Result rc; + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.Flush(); + rc = handle.File.Flush(); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, handle, string.Empty); } else { - handle.File.Flush(); + rc = handle.File.Flush(); } + + return rc; } - public long GetFileSize(FileHandle handle) + public Result GetFileSize(out long fileSize, FileHandle handle) { - handle.File.GetSize(out long fileSize).ThrowIfFailure(); - - return fileSize; + return handle.File.GetSize(out fileSize); } - public void SetFileSize(FileHandle handle, long size) + public Result SetFileSize(FileHandle handle, long size) { + Result rc; + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.SetSize(size); + rc = handle.File.SetSize(size); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, handle, $", size: {size}"); } else { - handle.File.SetSize(size); + rc = handle.File.SetSize(size); } + + return rc; } public OpenMode GetFileOpenMode(FileHandle handle) @@ -468,9 +504,11 @@ namespace LibHac.FsClient // ========================== // Operations on directory handles // ========================== - public int GetDirectoryEntryCount(DirectoryHandle handle) + public Result GetDirectoryEntryCount(out long count, DirectoryHandle handle) { - return handle.Directory.GetEntryCount(); + count = handle.Directory.GetEntryCount(); + + return Result.Success; } public IEnumerable ReadDirectory(DirectoryHandle handle) diff --git a/src/LibHac/FsClient/FileSystemManagerUtils.cs b/src/LibHac/FsClient/FileSystemManagerUtils.cs index bce4b6e4..60d3244c 100644 --- a/src/LibHac/FsClient/FileSystemManagerUtils.cs +++ b/src/LibHac/FsClient/FileSystemManagerUtils.cs @@ -7,10 +7,13 @@ namespace LibHac.FsClient { public static class FileSystemManagerUtils { - public static void CopyDirectory(this FileSystemManager fs, string sourcePath, string destPath, + public static Result CopyDirectory(this FileSystemManager fs, string sourcePath, string destPath, CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null) { - using (DirectoryHandle sourceHandle = fs.OpenDirectory(sourcePath, OpenDirectoryMode.All)) + Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + using (sourceHandle) { foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) { @@ -21,7 +24,8 @@ namespace LibHac.FsClient { fs.EnsureDirectoryExists(subDstPath); - fs.CopyDirectory(subSrcPath, subDstPath, options, logger); + rc = fs.CopyDirectory(subSrcPath, subDstPath, options, logger); + if (rc.IsFailure()) return rc; } if (entry.Type == DirectoryEntryType.File) @@ -29,46 +33,65 @@ namespace LibHac.FsClient logger?.LogMessage(subSrcPath); fs.CreateOrOverwriteFile(subDstPath, entry.Size, options); - fs.CopyFile(subSrcPath, subDstPath, logger); + rc = fs.CopyFile(subSrcPath, subDstPath, logger); + if (rc.IsFailure()) return rc; } } } + + return Result.Success; } - public static void CopyFile(this FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) + public static Result CopyFile(this FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) { - using (FileHandle sourceHandle = fs.OpenFile(sourcePath, OpenMode.Read)) - using (FileHandle destHandle = fs.OpenFile(destPath, OpenMode.Write | OpenMode.AllowAppend)) + Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read); + if (rc.IsFailure()) return rc; + + using (sourceHandle) { - const int maxBufferSize = 0x10000; + rc = fs.OpenFile(out FileHandle destHandle, destPath, OpenMode.Write | OpenMode.AllowAppend); + if (rc.IsFailure()) return rc; - long fileSize = fs.GetFileSize(sourceHandle); - int bufferSize = (int)Math.Min(maxBufferSize, fileSize); - - logger?.SetTotal(fileSize); - - byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - try + using (destHandle) { - for (long offset = 0; offset < fileSize; offset += bufferSize) + const int maxBufferSize = 0x10000; + + rc = fs.GetFileSize(out long fileSize, sourceHandle); + if (rc.IsFailure()) return rc; + + int bufferSize = (int)Math.Min(maxBufferSize, fileSize); + + logger?.SetTotal(fileSize); + + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + try { - int toRead = (int)Math.Min(fileSize - offset, bufferSize); - Span buf = buffer.AsSpan(0, toRead); + for (long offset = 0; offset < fileSize; offset += bufferSize) + { + int toRead = (int)Math.Min(fileSize - offset, bufferSize); + Span buf = buffer.AsSpan(0, toRead); - fs.ReadFile(sourceHandle, buf, offset); - fs.WriteFile(destHandle, buf, offset); + rc = fs.ReadFile(out long _, sourceHandle, buf, offset); + if (rc.IsFailure()) return rc; - logger?.ReportAdd(toRead); + rc = fs.WriteFile(destHandle, buf, offset); + if (rc.IsFailure()) return rc; + + logger?.ReportAdd(toRead); + } + } + finally + { + ArrayPool.Shared.Return(buffer); + logger?.SetTotal(0); } - } - finally - { - ArrayPool.Shared.Return(buffer); - logger?.SetTotal(0); - } - fs.FlushFile(destHandle); + rc = fs.FlushFile(destHandle); + if (rc.IsFailure()) return rc; + } } + + return Result.Success; } public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path) @@ -86,7 +109,9 @@ namespace LibHac.FsClient bool ignoreCase = searchOptions.HasFlag(SearchOptions.CaseInsensitive); bool recurse = searchOptions.HasFlag(SearchOptions.RecurseSubdirectories); - using (DirectoryHandle sourceHandle = fs.OpenDirectory(path, OpenDirectoryMode.All)) + fs.OpenDirectory(out DirectoryHandle sourceHandle, path, OpenDirectoryMode.All).ThrowIfFailure(); + + using (sourceHandle) { foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) { @@ -112,12 +137,16 @@ namespace LibHac.FsClient public static bool DirectoryExists(this FileSystemManager fs, string path) { - return fs.GetEntryType(path) == DirectoryEntryType.Directory; + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + + return (rc.IsSuccess() && type == DirectoryEntryType.Directory); } public static bool FileExists(this FileSystemManager fs, string path) { - return fs.GetEntryType(path) == DirectoryEntryType.File; + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + + return (rc.IsSuccess() && type == DirectoryEntryType.File); } public static void EnsureDirectoryExists(this FileSystemManager fs, string path) diff --git a/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs index f00dde73..d7c50ff5 100644 --- a/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs @@ -5,6 +5,6 @@ namespace LibHac.FsService.Creators public interface IHostFileSystemCreator { Result Create(out IFileSystem fileSystem, bool someBool); - Result Create(out IFileSystem fileSystem, string path, bool someBool); + Result Create(out IFileSystem fileSystem, string path, bool openCaseSensitive); } } \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs index 7de7c485..e0858de4 100644 --- a/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs @@ -4,7 +4,7 @@ namespace LibHac.FsService.Creators { public interface ITargetManagerFileSystemCreator { - Result Create(out IFileSystem fileSystem, bool someBool); + Result Create(out IFileSystem fileSystem, bool openCaseSensitive); Result GetCaseSensitivePath(out bool isSuccess, ref string path); } } \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs index 5f19cdc4..ad2ecf8b 100644 --- a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs @@ -6,16 +6,10 @@ namespace LibHac.FsService.Creators { public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, string path) { - try - { - baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directory); - } - catch (HorizonResultException ex) - { - subDirFileSystem = default; + subDirFileSystem = default; - return ex.ResultValue; - } + Result rc = baseFileSystem.OpenDirectory(out IDirectory _, path, OpenDirectoryMode.Directory); + if (rc.IsFailure()) return rc; subDirFileSystem = new SubdirectoryFileSystem(baseFileSystem, path); diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs index 0a0b8a62..8ac791bd 100644 --- a/src/LibHac/FsService/Util.cs +++ b/src/LibHac/FsService/Util.cs @@ -11,11 +11,13 @@ namespace LibHac.FsService if (!createPathIfMissing) { - if (path == null) return ResultFs.NullArgument; + if (path == null) return ResultFs.NullArgument.Log(); - if (baseFileSystem.GetEntryType(path) != DirectoryEntryType.Directory) + Result rc = baseFileSystem.GetEntryType(out DirectoryEntryType entryType, path); + + if (rc.IsFailure() || entryType != DirectoryEntryType.Directory) { - return ResultFs.PathNotFound; + return ResultFs.PathNotFound.Log(); } } @@ -28,16 +30,10 @@ namespace LibHac.FsService { subFileSystem = default; - if (path == null) return ResultFs.NullArgument; + if (path == null) return ResultFs.NullArgument.Log(); - try - { - baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directory); - } - catch (HorizonResultException ex) - { - return ex.ResultValue; - } + Result rc = baseFileSystem.OpenDirectory(out IDirectory _, path, OpenDirectoryMode.Directory); + if (rc.IsFailure()) return rc; subFileSystem = new SubdirectoryFileSystem(baseFileSystem, path); diff --git a/src/LibHac/SwitchFs.cs b/src/LibHac/SwitchFs.cs index 98b42155..2f91685c 100644 --- a/src/LibHac/SwitchFs.cs +++ b/src/LibHac/SwitchFs.cs @@ -67,9 +67,10 @@ namespace LibHac private void OpenAllNcas() { + ContentFs.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.All).ThrowIfFailure(); + // Todo: give warning if directories named "*.nca" are found or manually fix the archive bit - IEnumerable files = ContentFs.OpenDirectory("/", OpenDirectoryMode.All) - .EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories) + IEnumerable files = rootDir.EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories) .Where(x => x.Type == DirectoryEntryType.File); foreach (DirectoryEntry fileEntry in files) @@ -77,9 +78,9 @@ namespace LibHac SwitchFsNca nca = null; try { - IStorage storage = ContentFs.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage(); + ContentFs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure(); - nca = new SwitchFsNca(new Nca(Keyset, storage)); + nca = new SwitchFsNca(new Nca(Keyset, ncaFile.AsStorage())); nca.NcaId = GetNcaFilename(fileEntry.Name, nca); string extension = nca.Nca.Header.ContentType == NcaContentType.Meta ? ".cnmt.nca" : ".nca"; @@ -115,7 +116,8 @@ namespace LibHac try { - IFile file = SaveFs.OpenFile(fileEntry.FullPath, OpenMode.Read); + SaveFs.OpenFile(out IFile file, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure(); + save = new SaveDataFileSystem(Keyset, file.AsStorage(), IntegrityCheckLevel.None, true); } catch (Exception ex) @@ -141,7 +143,7 @@ namespace LibHac IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); string cnmtPath = fs.EnumerateEntries("*.cnmt").Single().FullPath; - IFile file = fs.OpenFile(cnmtPath, OpenMode.Read); + fs.OpenFile(out IFile file, cnmtPath, OpenMode.Read).ThrowIfFailure(); var metadata = new Cnmt(file.AsStream()); title.Id = metadata.TitleId; @@ -185,7 +187,7 @@ namespace LibHac foreach (Title title in Titles.Values.Where(x => x.ControlNca != null)) { IFileSystem romfs = title.ControlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - IFile control = romfs.OpenFile("control.nacp", OpenMode.Read); + romfs.OpenFile(out IFile control, "control.nacp", OpenMode.Read).ThrowIfFailure(); title.Control = new Nacp(control.AsStream()); diff --git a/src/LibHac/Xci.cs b/src/LibHac/Xci.cs index 3587f12f..9fe8c7f1 100644 --- a/src/LibHac/Xci.cs +++ b/src/LibHac/Xci.cs @@ -28,8 +28,8 @@ namespace LibHac XciPartition root = GetRootPartition(); if (type == XciPartitionType.Root) return root; - IStorage partitionStorage = root.OpenFile(type.GetFileName(), OpenMode.Read).AsStorage(); - return new XciPartition(partitionStorage); + root.OpenFile(out IFile partitionFile, type.GetFileName(), OpenMode.Read).ThrowIfFailure(); + return new XciPartition(partitionFile.AsStorage()); } private XciPartition GetRootPartition() diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index 0f41f501..0e3d2c1b 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -26,7 +26,9 @@ namespace hactoolnet private static void CopyDirectoryWithProgressInternal(FileSystemManager fs, string sourcePath, string destPath, CreateFileOptions options, IProgressReport logger) { - using (DirectoryHandle sourceHandle = fs.OpenDirectory(sourcePath, OpenDirectoryMode.All)) + fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All).ThrowIfFailure(); + + using (sourceHandle) { foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) { @@ -63,37 +65,53 @@ namespace hactoolnet return size; } - public static void CopyFileWithProgress(FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) + public static Result CopyFileWithProgress(FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) { - using (FileHandle sourceHandle = fs.OpenFile(sourcePath, OpenMode.Read)) - using (FileHandle destHandle = fs.OpenFile(destPath, OpenMode.Write | OpenMode.AllowAppend)) + Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read); + if (rc.IsFailure()) return rc; + + using (sourceHandle) { - const int maxBufferSize = 1024 * 1024; + rc = fs.OpenFile(out FileHandle destHandle, destPath, OpenMode.Write | OpenMode.AllowAppend); + if (rc.IsFailure()) return rc; - long fileSize = fs.GetFileSize(sourceHandle); - int bufferSize = (int)Math.Min(maxBufferSize, fileSize); - - byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - try + using (destHandle) { - for (long offset = 0; offset < fileSize; offset += bufferSize) + const int maxBufferSize = 1024 * 1024; + + rc = fs.GetFileSize(out long fileSize, sourceHandle); + if (rc.IsFailure()) return rc; + + int bufferSize = (int)Math.Min(maxBufferSize, fileSize); + + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + try { - int toRead = (int)Math.Min(fileSize - offset, bufferSize); - Span buf = buffer.AsSpan(0, toRead); + for (long offset = 0; offset < fileSize; offset += bufferSize) + { + int toRead = (int)Math.Min(fileSize - offset, bufferSize); + Span buf = buffer.AsSpan(0, toRead); - fs.ReadFile(sourceHandle, buf, offset); - fs.WriteFile(destHandle, buf, offset); + rc = fs.ReadFile(out long _, sourceHandle, buf, offset); + if (rc.IsFailure()) return rc; - logger?.ReportAdd(toRead); + rc = fs.WriteFile(destHandle, buf, offset); + if (rc.IsFailure()) return rc; + + logger?.ReportAdd(toRead); + } + } + finally + { + ArrayPool.Shared.Return(buffer); } - } - finally - { - ArrayPool.Shared.Return(buffer); - } - fs.FlushFile(destHandle); + rc = fs.FlushFile(destHandle); + if (rc.IsFailure()) return rc; + } } + + return Result.Success; } } } diff --git a/src/hactoolnet/ProcessDelta.cs b/src/hactoolnet/ProcessDelta.cs index d8c1c4b7..b03dde02 100644 --- a/src/hactoolnet/ProcessDelta.cs +++ b/src/hactoolnet/ProcessDelta.cs @@ -33,7 +33,9 @@ namespace hactoolnet throw new FileNotFoundException("Specified NCA does not contain a delta fragment"); } - deltaStorage = fs.OpenFile(FragmentFileName, OpenMode.Read).AsStorage(); + fs.OpenFile(out IFile deltaFragmentFile, FragmentFileName, OpenMode.Read).ThrowIfFailure(); + + deltaStorage = deltaFragmentFile.AsStorage(); } catch (InvalidDataException) { } // Ignore non-NCA3 files } diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index da1caf58..5b301917 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -210,8 +210,8 @@ namespace hactoolnet IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid); if (!pfs.FileExists("main.npdm")) return Validity.Unchecked; - IFile npdmStorage = pfs.OpenFile("main.npdm", OpenMode.Read); - var npdm = new NpdmBinary(npdmStorage.AsStream()); + pfs.OpenFile(out IFile npdmFile, "main.npdm", OpenMode.Read).ThrowIfFailure(); + var npdm = new NpdmBinary(npdmFile.AsStream()); return nca.Header.VerifySignature2(npdm.AciD.Rsa2048Modulus); } diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index 6be16758..e95f8340 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -62,7 +62,9 @@ namespace hactoolnet using (IFile inFile = new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read)) { - using (IFile outFile = save.OpenFile(destFilename, OpenMode.ReadWrite)) + save.OpenFile(out IFile outFile, destFilename, OpenMode.ReadWrite).ThrowIfFailure(); + + using (outFile) { inFile.GetSize(out long inFileSize).ThrowIfFailure(); outFile.GetSize(out long outFileSize).ThrowIfFailure(); @@ -100,7 +102,7 @@ namespace hactoolnet { if (signNeeded) { - save.Commit(ctx.Keyset); + save.Commit(ctx.Keyset).ThrowIfFailure(); signNeeded = false; } } @@ -114,7 +116,7 @@ namespace hactoolnet if (signNeeded) { - if (save.Commit(ctx.Keyset)) + if (save.Commit(ctx.Keyset).IsSuccess()) { ctx.Logger.LogMessage("Successfully signed save file"); } @@ -310,7 +312,7 @@ namespace hactoolnet var sb = new StringBuilder(); sb.AppendLine(); - long freeSpace = save.GetFreeSpaceSize(""); + save.GetFreeSpaceSize(out long freeSpace, "").ThrowIfFailure(); sb.AppendLine("Savefile:"); PrintItem(sb, colLen, $"CMAC Signature{save.Header.SignatureValidity.GetValidityString()}:", save.Header.Cmac); From 104312bf0632299775bdf4691dbfe8b2ba2f525a Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 8 Sep 2019 15:16:37 -0500 Subject: [PATCH 13/46] Log result codes in access log --- src/LibHac/FsClient/FileSystemManager.cs | 65 ++++++++++--------- src/LibHac/FsClient/FileSystemManagerUtils.cs | 11 ++++ src/LibHac/FsClient/IAccessLog.cs | 2 +- src/LibHac/FsClient/SdCardAccessLog.cs | 2 +- src/hactoolnet/AccessLog.cs | 16 ++--- 5 files changed, 55 insertions(+), 41 deletions(-) diff --git a/src/LibHac/FsClient/FileSystemManager.cs b/src/LibHac/FsClient/FileSystemManager.cs index 7b4688bf..08d87565 100644 --- a/src/LibHac/FsClient/FileSystemManager.cs +++ b/src/LibHac/FsClient/FileSystemManager.cs @@ -44,20 +44,23 @@ namespace LibHac.FsClient public void Unmount(string mountName) { - MountTable.Find(mountName, out FileSystemAccessor fileSystem).ThrowIfFailure(); + Result rc; - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + if (IsEnabledAccessLog() && this.IsEnabledFileSystemAccessorAccessLog(mountName)) { TimeSpan startTime = Time.GetCurrent(); - MountTable.Unmount(mountName); - TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", name: \"{mountName}\""); + rc = MountTable.Unmount(mountName); + + TimeSpan endTime = Time.GetCurrent(); + OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\""); } else { - MountTable.Unmount(mountName); + rc = MountTable.Unmount(mountName); } + + rc.ThrowIfFailure(); } public void SetAccessLog(bool isEnabled, IAccessLog accessLog = null) @@ -78,7 +81,7 @@ namespace LibHac.FsClient rc = fileSystem.CreateDirectory(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); } else { @@ -104,7 +107,7 @@ namespace LibHac.FsClient rc = fileSystem.CreateFile(subPath.ToString(), size, options); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", path: \"{path}\", size: {size}"); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\", size: {size}"); } else { @@ -125,7 +128,7 @@ namespace LibHac.FsClient rc = fileSystem.DeleteDirectory(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); } else { @@ -146,7 +149,7 @@ namespace LibHac.FsClient rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); } else { @@ -167,7 +170,7 @@ namespace LibHac.FsClient rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); } else { @@ -188,7 +191,7 @@ namespace LibHac.FsClient rc = fileSystem.DeleteFile(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); } else { @@ -217,7 +220,7 @@ namespace LibHac.FsClient rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); } else { @@ -246,7 +249,7 @@ namespace LibHac.FsClient rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); } else { @@ -269,7 +272,7 @@ namespace LibHac.FsClient rc = fileSystem.GetEntryType(out type, subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); } else { @@ -293,7 +296,7 @@ namespace LibHac.FsClient handle = new FileHandle(file); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); + OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); } else { @@ -318,7 +321,7 @@ namespace LibHac.FsClient handle = new DirectoryHandle(dir); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); + OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); } else { @@ -370,7 +373,7 @@ namespace LibHac.FsClient rc = fileSystem.Commit(); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, $", name: \"{mountName}\""); + OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\""); } else { @@ -398,7 +401,7 @@ namespace LibHac.FsClient rc = handle.File.Read(out bytesRead, offset, destination, option); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, handle, $", offset: {offset}, size: {destination.Length}"); + OutputAccessLog(rc, startTime, endTime, handle, $", offset: {offset}, size: {destination.Length}"); } else { @@ -425,7 +428,7 @@ namespace LibHac.FsClient string optionString = (option & WriteOption.Flush) == 0 ? "" : $", write_option: {option}"; - OutputAccessLog(startTime, endTime, handle, $", offset: {offset}, size: {source.Length}{optionString}"); + OutputAccessLog(rc, startTime, endTime, handle, $", offset: {offset}, size: {source.Length}{optionString}"); } else { @@ -445,7 +448,7 @@ namespace LibHac.FsClient rc = handle.File.Flush(); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, handle, string.Empty); + OutputAccessLog(rc, startTime, endTime, handle, string.Empty); } else { @@ -470,7 +473,7 @@ namespace LibHac.FsClient rc = handle.File.SetSize(size); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, handle, $", size: {size}"); + OutputAccessLog(rc, startTime, endTime, handle, $", size: {size}"); } else { @@ -493,7 +496,7 @@ namespace LibHac.FsClient handle.File.Dispose(); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, handle, string.Empty); + OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); } else { @@ -519,7 +522,7 @@ namespace LibHac.FsClient IEnumerable entries = handle.Directory.Read(); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, handle, string.Empty); + OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); return entries; } @@ -534,7 +537,7 @@ namespace LibHac.FsClient handle.Directory.Dispose(); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(startTime, endTime, handle, string.Empty); + OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); } else { @@ -606,19 +609,19 @@ namespace LibHac.FsClient return handle.Directory.Parent.IsAccessLogEnabled; } - internal void OutputAccessLog(TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "") + internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "") { - AccessLog.Log(startTime, endTime, 0, message, caller); + AccessLog.Log(result, startTime, endTime, 0, message, caller); } - internal void OutputAccessLog(TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "") + internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "") { - AccessLog.Log(startTime, endTime, handle.GetId(), message, caller); + AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller); } - internal void OutputAccessLog(TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "") + internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "") { - AccessLog.Log(startTime, endTime, handle.GetId(), message, caller); + AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller); } } } diff --git a/src/LibHac/FsClient/FileSystemManagerUtils.cs b/src/LibHac/FsClient/FileSystemManagerUtils.cs index 60d3244c..31d6fe55 100644 --- a/src/LibHac/FsClient/FileSystemManagerUtils.cs +++ b/src/LibHac/FsClient/FileSystemManagerUtils.cs @@ -2,6 +2,7 @@ using System.Buffers; using System.Collections.Generic; using LibHac.Fs; +using LibHac.FsClient.Accessors; namespace LibHac.FsClient { @@ -202,5 +203,15 @@ namespace LibHac.FsClient fs.CreateFile(path, size, CreateFileOptions.None); } + + internal static bool IsEnabledFileSystemAccessorAccessLog(this FileSystemManager fs, string mountName) + { + if (fs.MountTable.Find(mountName, out FileSystemAccessor accessor).IsFailure()) + { + return true; + } + + return accessor.IsAccessLogEnabled; + } } } diff --git a/src/LibHac/FsClient/IAccessLog.cs b/src/LibHac/FsClient/IAccessLog.cs index b145e32f..fbf83d5a 100644 --- a/src/LibHac/FsClient/IAccessLog.cs +++ b/src/LibHac/FsClient/IAccessLog.cs @@ -5,6 +5,6 @@ namespace LibHac.FsClient { public interface IAccessLog { - void Log(TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = ""); + void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = ""); } } \ No newline at end of file diff --git a/src/LibHac/FsClient/SdCardAccessLog.cs b/src/LibHac/FsClient/SdCardAccessLog.cs index d3b97ae9..a69dc12a 100644 --- a/src/LibHac/FsClient/SdCardAccessLog.cs +++ b/src/LibHac/FsClient/SdCardAccessLog.cs @@ -8,7 +8,7 @@ namespace LibHac.FsClient /// public class SdCardAccessLog : IAccessLog { - public void Log(TimeSpan startTime, TimeSpan endTime, int handleId, string message, string caller = "") + public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, string caller = "") { throw new NotImplementedException(); } diff --git a/src/hactoolnet/AccessLog.cs b/src/hactoolnet/AccessLog.cs index f7f505c0..617e7eaf 100644 --- a/src/hactoolnet/AccessLog.cs +++ b/src/hactoolnet/AccessLog.cs @@ -8,9 +8,9 @@ namespace hactoolnet { public class ConsoleAccessLog : IAccessLog { - public void Log(TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "") + public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "") { - Console.WriteLine(CommonAccessLog.BuildLogLine(startTime, endTime, handleId, message, caller)); + Console.WriteLine(CommonAccessLog.BuildLogLine(result, startTime, endTime, handleId, message, caller)); } } @@ -22,9 +22,9 @@ namespace hactoolnet Logger = logger; } - public void Log(TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "") + public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "") { - Logger.LogMessage(CommonAccessLog.BuildLogLine(startTime, endTime, handleId, message, caller)); + Logger.LogMessage(CommonAccessLog.BuildLogLine(result, startTime, endTime, handleId, message, caller)); } } @@ -37,18 +37,18 @@ namespace hactoolnet Logger = logger; } - public void Log(TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "") + public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "") { - Logger.WriteLine(CommonAccessLog.BuildLogLine(startTime, endTime, handleId, message, caller)); + Logger.WriteLine(CommonAccessLog.BuildLogLine(result, startTime, endTime, handleId, message, caller)); } } public static class CommonAccessLog { - public static string BuildLogLine(TimeSpan startTime, TimeSpan endTime, int handleId, string message, + public static string BuildLogLine(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, string caller) { - return $"FS_ACCESS: {{ start: {(long)startTime.TotalMilliseconds,9}, end: {(long)endTime.TotalMilliseconds,9}, handle: 0x{handleId:x8}, function: \"{caller}\"{message} }}"; + return $"FS_ACCESS: {{ start: {(long)startTime.TotalMilliseconds,9}, end: {(long)endTime.TotalMilliseconds,9}, result: 0x{result.Value:x8}, handle: 0x{handleId:x8}, function: \"{caller}\"{message} }}"; } } } From 734d86d336bb7b755aaf252bbe681fc634082e0d Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 14 Sep 2019 18:35:25 -0500 Subject: [PATCH 14/46] Change IDirectory to match the interface in FS --- src/LibHac/Common/BlitStruct.cs | 52 +++++++++ src/LibHac/Common/SpanHelpers.cs | 35 ++++++ src/LibHac/Common/StringUtils.cs | 85 +++++++++++++++ src/LibHac/Fs/AesXtsDirectory.cs | 87 ++++++++------- src/LibHac/Fs/AesXtsFileHeader.cs | 2 +- src/LibHac/Fs/AesXtsFileSystem.cs | 6 +- src/LibHac/Fs/ConcatenationDirectory.cs | 86 ++++++++++----- src/LibHac/Fs/ConcatenationFileSystem.cs | 5 +- src/LibHac/Fs/DirectoryEntry.cs | 21 +++- src/LibHac/Fs/DirectorySaveDataFileSystem.cs | 8 +- src/LibHac/Fs/DirectoryUtils.cs | 85 +++++++++++++++ src/LibHac/Fs/FileSystemExtensions.cs | 100 +++++++++--------- src/LibHac/Fs/FsPath.cs | 16 +++ src/LibHac/Fs/IDirectory.cs | 40 +++---- src/LibHac/Fs/IFileSystem.cs | 5 +- src/LibHac/Fs/LayeredFileSystem.cs | 2 +- src/LibHac/Fs/LayeredFileSystemDirectory.cs | 51 +++++---- src/LibHac/Fs/LocalDirectory.cs | 45 +++++--- src/LibHac/Fs/PartitionDirectory.cs | 53 +++++++--- src/LibHac/Fs/PartitionFileSystemBuilder.cs | 4 +- src/LibHac/Fs/PathTools.cs | 2 + src/LibHac/Fs/ReadOnlyDirectory.cs | 22 ---- src/LibHac/Fs/ReadOnlyFileSystem.cs | 8 +- src/LibHac/Fs/RomFs/RomFsBuilder.cs | 2 +- src/LibHac/Fs/RomFs/RomFsDirectory.cs | 84 +++++++++------ src/LibHac/Fs/RomFs/RomFsFileSystem.cs | 2 +- src/LibHac/Fs/Save/SaveDataDirectory.cs | 84 +++++++++------ src/LibHac/Fs/Save/SaveDataFileSystemCore.cs | 9 +- src/LibHac/Fs/SubdirectoryFileSystem.cs | 5 +- .../Fs/SubdirectoryFileSystemDirectory.cs | 34 ------ .../FsClient/Accessors/DirectoryAccessor.cs | 20 +++- .../FsClient/Accessors/FileSystemAccessor.cs | 2 +- .../FsClient/FileSystemClient.Directory.cs | 2 +- src/LibHac/FsClient/FileSystemManager.cs | 28 ++++- src/LibHac/FsClient/FileSystemManagerUtils.cs | 14 +-- src/LibHac/LibHac.csproj | 1 + src/LibHac/SwitchFs.cs | 10 +- src/hactoolnet/FsUtils.cs | 4 +- src/hactoolnet/ProcessNca.cs | 2 +- src/hactoolnet/ProcessRomfs.cs | 2 +- src/hactoolnet/ProcessSave.cs | 4 +- src/hactoolnet/ProcessSwitchFs.cs | 4 +- 42 files changed, 738 insertions(+), 395 deletions(-) create mode 100644 src/LibHac/Common/BlitStruct.cs create mode 100644 src/LibHac/Common/SpanHelpers.cs create mode 100644 src/LibHac/Common/StringUtils.cs create mode 100644 src/LibHac/Fs/DirectoryUtils.cs create mode 100644 src/LibHac/Fs/FsPath.cs delete mode 100644 src/LibHac/Fs/ReadOnlyDirectory.cs delete mode 100644 src/LibHac/Fs/SubdirectoryFileSystemDirectory.cs diff --git a/src/LibHac/Common/BlitStruct.cs b/src/LibHac/Common/BlitStruct.cs new file mode 100644 index 00000000..70e4dad8 --- /dev/null +++ b/src/LibHac/Common/BlitStruct.cs @@ -0,0 +1,52 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace LibHac.Common +{ + public ref struct BlitStruct where T : unmanaged + { + private readonly Span _buffer; + + public int Length => _buffer.Length; + + public ref T Value => ref _buffer[0]; + public ref T this[int index] => ref _buffer[index]; + + public BlitStruct(Span data) + { + _buffer = data; + + Debug.Assert(_buffer.Length != 0); + } + + public BlitStruct(Span data) + { + _buffer = MemoryMarshal.Cast(data); + + Debug.Assert(_buffer.Length != 0); + } + + public BlitStruct(ref T data) + { + _buffer = SpanHelpers.AsSpan(ref data); + } + + public Span GetByteSpan() + { + return MemoryMarshal.Cast(_buffer); + } + + public Span GetByteSpan(int elementIndex) + { + Span element = _buffer.Slice(elementIndex, 1); + return MemoryMarshal.Cast(element); + } + + public static int QueryByteLength(int elementCount) + { + return Unsafe.SizeOf() * elementCount; + } + } +} diff --git a/src/LibHac/Common/SpanHelpers.cs b/src/LibHac/Common/SpanHelpers.cs new file mode 100644 index 00000000..ce8aabd4 --- /dev/null +++ b/src/LibHac/Common/SpanHelpers.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace LibHac.Common +{ + public static class SpanHelpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#if NETCOREAPP + public static Span CreateSpan(ref T reference, int length) + { + return MemoryMarshal.CreateSpan(ref reference, length); + } +#else + public static unsafe Span CreateSpan(ref T reference, int length) + { + return new Span(Unsafe.AsPointer(ref reference), length); + } +#endif + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(ref T reference) where T : unmanaged + { + return CreateSpan(ref reference, 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsByteSpan(ref T reference) where T : unmanaged + { + Span span = AsSpan(ref reference); + return MemoryMarshal.Cast(span); + } + } +} diff --git a/src/LibHac/Common/StringUtils.cs b/src/LibHac/Common/StringUtils.cs new file mode 100644 index 00000000..364d8396 --- /dev/null +++ b/src/LibHac/Common/StringUtils.cs @@ -0,0 +1,85 @@ +using System; +using System.Text; + +namespace LibHac.Common +{ + public static class StringUtils + { + public static int Copy(Span dest, ReadOnlySpan source) + { + int maxLen = Math.Min(dest.Length, source.Length); + + int i; + for (i = 0; i < maxLen && source[i] != 0; i++) + dest[i] = source[i]; + + if (i < dest.Length) + { + dest[i] = 0; + } + + return i; + } + + public static int GetLength(ReadOnlySpan s) + { + int i = 0; + + while (i < s.Length && s[i] != 0) + { + i++; + } + + return i; + } + + /// + /// Concatenates 2 byte strings. + /// + /// + /// + /// The length of the resulting string. + /// This function appends the source string to the end of the null-terminated destination string. + /// If the destination buffer is not large enough to contain the resulting string, + /// bytes from the source string will be appended to the destination string util the buffer is full. + /// If the length of the final string is the same length of the destination buffer, + /// no null terminating byte will be written to the end of the string. + public static int Concat(Span dest, ReadOnlySpan source) + { + return Concat(dest, GetLength(dest), source); + } + + public static int Concat(Span dest, int destLength, ReadOnlySpan source) + { + int iDest = destLength; + + for (int i = 0; iDest < dest.Length && i < source.Length && source[i] != 0; i++, iDest++) + { + dest[iDest] = source[i]; + } + + if (iDest < dest.Length) + { + dest[iDest] = 0; + } + + return iDest; + } + + public static string FromUtf8Z(this Span value) => FromUtf8Z((ReadOnlySpan)value); + + public static string FromUtf8Z(this ReadOnlySpan value) + { + int i; + for (i = 0; i < value.Length && value[i] != 0; i++) { } + + value = value.Slice(0, i); + +#if STRING_SPAN + return Encoding.UTF8.GetString(value); +#else + return Encoding.UTF8.GetString(value.ToArray()); +#endif + } + } +} diff --git a/src/LibHac/Fs/AesXtsDirectory.cs b/src/LibHac/Fs/AesXtsDirectory.cs index 67106723..a8bd71cc 100644 --- a/src/LibHac/Fs/AesXtsDirectory.cs +++ b/src/LibHac/Fs/AesXtsDirectory.cs @@ -1,85 +1,90 @@ using System; -using System.Collections.Generic; +using LibHac.Common; namespace LibHac.Fs { public class AesXtsDirectory : IDirectory { - IFileSystem IDirectory.ParentFileSystem => ParentFileSystem; - public AesXtsFileSystem ParentFileSystem { get; } - - public string FullPath { get; } - public OpenDirectoryMode Mode { get; } + private string Path { get; } + private OpenDirectoryMode Mode { get; } private IFileSystem BaseFileSystem { get; } private IDirectory BaseDirectory { get; } - public AesXtsDirectory(AesXtsFileSystem parentFs, IDirectory baseDir, OpenDirectoryMode mode) + public AesXtsDirectory(IFileSystem baseFs, IDirectory baseDir, string path, OpenDirectoryMode mode) { - ParentFileSystem = parentFs; + BaseFileSystem = baseFs; BaseDirectory = baseDir; Mode = mode; - BaseFileSystem = BaseDirectory.ParentFileSystem; - FullPath = BaseDirectory.FullPath; + Path = path; } - public IEnumerable Read() + public Result Read(out long entriesRead, Span entryBuffer) { - foreach (DirectoryEntry entry in BaseDirectory.Read()) - { - if (entry.Type == DirectoryEntryType.Directory) - { - yield return entry; - } - else - { - // todo: FS returns invalid file entries with a size of 0 - long size = GetAesXtsFileSize(entry.FullPath); - if (size == -1) continue; + Result rc = BaseDirectory.Read(out entriesRead, entryBuffer); + if (rc.IsFailure()) return rc; - yield return new DirectoryEntry(entry.Name, entry.FullPath, entry.Type, size); + for (int i = 0; i < entriesRead; i++) + { + ref DirectoryEntry entry = ref entryBuffer[i]; + + if (entry.Type == DirectoryEntryType.File) + { + if (Mode.HasFlag(OpenDirectoryMode.NoFileSize)) + { + entry.Size = 0; + } + else + { + string entryName = Util.GetUtf8StringNullTerminated(entry.Name); + entry.Size = GetAesXtsFileSize(PathTools.Combine(Path, entryName)); + } } } + + return Result.Success; } - public int GetEntryCount() + public Result GetEntryCount(out long entryCount) { - return BaseDirectory.GetEntryCount(); + return BaseDirectory.GetEntryCount(out entryCount); } /// - /// Reads the size of a NAX0 file from its header. Returns -1 on error. + /// Reads the size of a NAX0 file from its header. Returns 0 on error. /// /// /// private long GetAesXtsFileSize(string path) { + const long magicOffset = 0x20; + const long fileSizeOffset = 0x48; + + // Todo: Remove try/catch when more code uses Result try { - BaseFileSystem.OpenFile(out IFile file, path, OpenMode.Read).ThrowIfFailure(); + Result rc = BaseFileSystem.OpenFile(out IFile file, path, OpenMode.Read); + if (rc.IsFailure()) return 0; using (file) { - file.GetSize(out long fileSize).ThrowIfFailure(); + uint magic = 0; + long fileSize = 0; + long bytesRead; - if (fileSize < 0x50) - { - return -1; - } + file.Read(out bytesRead, magicOffset, SpanHelpers.AsByteSpan(ref magic), ReadOption.None); + if (bytesRead != sizeof(uint) || magic != AesXtsFileHeader.AesXtsFileMagic) return 0; - // todo: Use result codes - var buffer = new byte[8]; + file.Read(out bytesRead, fileSizeOffset, SpanHelpers.AsByteSpan(ref fileSize), ReadOption.None); + if (bytesRead != sizeof(long) || magic != AesXtsFileHeader.AesXtsFileMagic) return 0; - file.Read(out long _, 0x20, buffer); - if (BitConverter.ToUInt32(buffer, 0) != 0x3058414E) return -1; - - file.Read(out long _, 0x48, buffer); - return BitConverter.ToInt64(buffer, 0); + return fileSize; } + } - catch (ArgumentOutOfRangeException) + catch (Exception) { - return -1; + return 0; } } } diff --git a/src/LibHac/Fs/AesXtsFileHeader.cs b/src/LibHac/Fs/AesXtsFileHeader.cs index 6c416179..292b39e0 100644 --- a/src/LibHac/Fs/AesXtsFileHeader.cs +++ b/src/LibHac/Fs/AesXtsFileHeader.cs @@ -7,7 +7,7 @@ namespace LibHac.Fs { public class AesXtsFileHeader { - private const uint AesXtsFileMagic = 0x3058414E; + internal const uint AesXtsFileMagic = 0x3058414E; public byte[] Signature { get; set; } = new byte[0x20]; public uint Magic { get; } public byte[] EncryptedKey1 { get; } = new byte[0x10]; diff --git a/src/LibHac/Fs/AesXtsFileSystem.cs b/src/LibHac/Fs/AesXtsFileSystem.cs index 3078bd05..529e4c5b 100644 --- a/src/LibHac/Fs/AesXtsFileSystem.cs +++ b/src/LibHac/Fs/AesXtsFileSystem.cs @@ -92,7 +92,7 @@ namespace LibHac.Fs Result rc = BaseFileSystem.OpenDirectory(out IDirectory baseDir, path, mode); if (rc.IsFailure()) return rc; - directory = new AesXtsDirectory(this, baseDir, mode); + directory = new AesXtsDirectory(BaseFileSystem, baseDir, path, mode); return Result.Success; } @@ -147,9 +147,7 @@ namespace LibHac.Fs private void RenameDirectoryImpl(string srcDir, string dstDir, bool doRollback) { - OpenDirectory(out IDirectory dir, dstDir, OpenDirectoryMode.All); - - foreach (DirectoryEntry entry in dir.Read()) + foreach (DirectoryEntryEx entry in this.EnumerateEntries(srcDir, "*")) { string subSrcPath = $"{srcDir}/{entry.Name}"; string subDstPath = $"{dstDir}/{entry.Name}"; diff --git a/src/LibHac/Fs/ConcatenationDirectory.cs b/src/LibHac/Fs/ConcatenationDirectory.cs index 90718113..88972e75 100644 --- a/src/LibHac/Fs/ConcatenationDirectory.cs +++ b/src/LibHac/Fs/ConcatenationDirectory.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using LibHac.Common; #if CROSS_PLATFORM using System.Runtime.InteropServices; @@ -8,58 +9,92 @@ namespace LibHac.Fs { public class ConcatenationDirectory : IDirectory { - IFileSystem IDirectory.ParentFileSystem => ParentFileSystem; - public string FullPath { get; } - public OpenDirectoryMode Mode { get; } + private string Path { get; } + private OpenDirectoryMode Mode { get; } private ConcatenationFileSystem ParentFileSystem { get; } + private IFileSystem BaseFileSystem { get; } private IDirectory ParentDirectory { get; } - public ConcatenationDirectory(ConcatenationFileSystem fs, IDirectory parentDirectory, OpenDirectoryMode mode) + public ConcatenationDirectory(ConcatenationFileSystem fs, IFileSystem baseFs, IDirectory parentDirectory, OpenDirectoryMode mode, string path) { ParentFileSystem = fs; + BaseFileSystem = baseFs; ParentDirectory = parentDirectory; Mode = mode; - FullPath = parentDirectory.FullPath; + Path = path; } - public IEnumerable Read() + public Result Read(out long entriesRead, Span entryBuffer) { - foreach (DirectoryEntry entry in ParentDirectory.Read()) + entriesRead = 0; + var entry = new DirectoryEntry(); + Span entrySpan = SpanHelpers.AsSpan(ref entry); + + int i; + for (i = 0; i < entryBuffer.Length; i++) { - bool isSplit = IsConcatenationFile(entry); + Result rc = ParentDirectory.Read(out long baseEntriesRead, entrySpan); + if (rc.IsFailure()) return rc; - if (!CanReturnEntry(entry, isSplit)) continue; + if (baseEntriesRead == 0) break; - if (isSplit) + // Check if the current open mode says we should return the entry + bool isConcatFile = IsConcatenationFile(entry); + if (!CanReturnEntry(entry, isConcatFile)) continue; + + if (isConcatFile) { entry.Type = DirectoryEntryType.File; - entry.Size = ParentFileSystem.GetConcatenationFileSize(entry.FullPath); - entry.Attributes = NxFileAttributes.None; + + if (!Mode.HasFlag(OpenDirectoryMode.NoFileSize)) + { + string entryName = Util.GetUtf8StringNullTerminated(entry.Name); + string entryFullPath = PathTools.Combine(Path, entryName); + + entry.Size = ParentFileSystem.GetConcatenationFileSize(entryFullPath); + } } - yield return entry; + entry.Attributes = NxFileAttributes.None; + + entryBuffer[i] = entry; } + + entriesRead = i; + return Result.Success; } - public int GetEntryCount() + public Result GetEntryCount(out long entryCount) { - int count = 0; + entryCount = 0; + long count = 0; - foreach (DirectoryEntry entry in ParentDirectory.Read()) + Result rc = BaseFileSystem.OpenDirectory(out IDirectory _, Path, + OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize); + if (rc.IsFailure()) return rc; + + var entry = new DirectoryEntry(); + Span entrySpan = SpanHelpers.AsSpan(ref entry); + + while (true) { - bool isSplit = IsConcatenationFile(entry); + rc = ParentDirectory.Read(out long baseEntriesRead, entrySpan); + if (rc.IsFailure()) return rc; - if (CanReturnEntry(entry, isSplit)) count++; + if (baseEntriesRead == 0) break; + + if (CanReturnEntry(entry, IsConcatenationFile(entry))) count++; } - return count; + entryCount = count; + return Result.Success; } - private bool CanReturnEntry(DirectoryEntry entry, bool isSplit) + private bool CanReturnEntry(DirectoryEntry entry, bool isConcatFile) { - return Mode.HasFlag(OpenDirectoryMode.File) && (entry.Type == DirectoryEntryType.File || isSplit) || - Mode.HasFlag(OpenDirectoryMode.Directory) && entry.Type == DirectoryEntryType.Directory && !isSplit; + return Mode.HasFlag(OpenDirectoryMode.File) && (entry.Type == DirectoryEntryType.File || isConcatFile) || + Mode.HasFlag(OpenDirectoryMode.Directory) && entry.Type == DirectoryEntryType.Directory && !isConcatFile; } private bool IsConcatenationFile(DirectoryEntry entry) @@ -71,7 +106,10 @@ namespace LibHac.Fs } else { - return ParentFileSystem.IsConcatenationFile(entry.FullPath); + string name = Util.GetUtf8StringNullTerminated(entry.Name); + string fullPath = PathTools.Combine(Path, name); + + return ParentFileSystem.IsConcatenationFile(fullPath); } #else return ConcatenationFileSystem.HasConcatenationFileAttribute(entry.Attributes); diff --git a/src/LibHac/Fs/ConcatenationFileSystem.cs b/src/LibHac/Fs/ConcatenationFileSystem.cs index 9c2a4471..b25f0f3e 100644 --- a/src/LibHac/Fs/ConcatenationFileSystem.cs +++ b/src/LibHac/Fs/ConcatenationFileSystem.cs @@ -80,7 +80,8 @@ namespace LibHac.Fs Result rc = BaseFileSystem.OpenDirectory(out IDirectory dir, path, OpenDirectoryMode.Directory); if (rc.IsFailure()) return false; - if (dir.GetEntryCount() > 0) return false; + rc = dir.GetEntryCount(out long subDirCount); + if (rc.IsFailure() || subDirCount > 0) return false; // Should be enough checks to avoid most false positives. Maybe return true; @@ -222,7 +223,7 @@ namespace LibHac.Fs Result rc = BaseFileSystem.OpenDirectory(out IDirectory parentDir, path, OpenDirectoryMode.All); if (rc.IsFailure()) return rc; - directory = new ConcatenationDirectory(this, parentDir, mode); + directory = new ConcatenationDirectory(this, BaseFileSystem, parentDir, mode, path); return Result.Success; } diff --git a/src/LibHac/Fs/DirectoryEntry.cs b/src/LibHac/Fs/DirectoryEntry.cs index fbefb8e7..62293fa7 100644 --- a/src/LibHac/Fs/DirectoryEntry.cs +++ b/src/LibHac/Fs/DirectoryEntry.cs @@ -1,8 +1,10 @@ using System; +using System.Runtime.InteropServices; +using LibHac.Common; namespace LibHac.Fs { - public class DirectoryEntry + public class DirectoryEntryEx { public string Name { get; set; } public string FullPath { get; set; } @@ -10,7 +12,7 @@ namespace LibHac.Fs public DirectoryEntryType Type { get; set; } public long Size { get; set; } - public DirectoryEntry(string name, string fullPath, DirectoryEntryType type, long size) + public DirectoryEntryEx(string name, string fullPath, DirectoryEntryType type, long size) { Name = name; FullPath = PathTools.Normalize(fullPath); @@ -19,7 +21,18 @@ namespace LibHac.Fs } } - public enum DirectoryEntryType + [StructLayout(LayoutKind.Explicit)] + public struct DirectoryEntry + { + [FieldOffset(0)] private byte _name; + [FieldOffset(0x301)] public NxFileAttributes Attributes; + [FieldOffset(0x304)] public DirectoryEntryType Type; + [FieldOffset(0x308)] public long Size; + + public Span Name => SpanHelpers.CreateSpan(ref _name, PathTools.MaxPathLength + 1); + } + + public enum DirectoryEntryType : byte { Directory, File, @@ -27,7 +40,7 @@ namespace LibHac.Fs } [Flags] - public enum NxFileAttributes + public enum NxFileAttributes : byte { None = 0, Directory = 1 << 0, diff --git a/src/LibHac/Fs/DirectorySaveDataFileSystem.cs b/src/LibHac/Fs/DirectorySaveDataFileSystem.cs index 9e4aca7e..70d74b54 100644 --- a/src/LibHac/Fs/DirectorySaveDataFileSystem.cs +++ b/src/LibHac/Fs/DirectorySaveDataFileSystem.cs @@ -212,13 +212,7 @@ namespace LibHac.Fs rc = BaseFs.CreateDirectory(dest); if (rc.IsFailure()) return rc; - rc = BaseFs.OpenDirectory(out IDirectory sourceDir, src, OpenDirectoryMode.All); - if (rc.IsFailure()) return rc; - - rc = BaseFs.OpenDirectory(out IDirectory destDir, dest, OpenDirectoryMode.All); - if (rc.IsFailure()) return rc; - - return sourceDir.CopyDirectory(destDir); + return this.CopyDirectory(this, src, dest); } internal void NotifyCloseWritableFile() diff --git a/src/LibHac/Fs/DirectoryUtils.cs b/src/LibHac/Fs/DirectoryUtils.cs new file mode 100644 index 00000000..2ff0839f --- /dev/null +++ b/src/LibHac/Fs/DirectoryUtils.cs @@ -0,0 +1,85 @@ +using System; +using LibHac.Common; + +namespace LibHac.Fs +{ + public static class DirectoryUtils + { + public delegate Result Blah(ReadOnlySpan path, ref DirectoryEntry entry); + + public static Result IterateDirectoryRecursivelyInternal(IFileSystem fs, Span workPath, + ref DirectoryEntry entry, Blah onEnterDir, Blah onExitDir, Blah onFile) + { + string currentPath = Util.GetUtf8StringNullTerminated(workPath); + + Result rc = fs.OpenDirectory(out IDirectory _, currentPath, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + onFile(workPath, ref entry); + + return Result.Success; + } + + public static Result IterateDirectoryRecursively(IFileSystem fs, ReadOnlySpan path, Blah onEnterDir, Blah onExitDir, Blah onFile) + { + return Result.Success; + } + + public static Result CopyDirectoryRecursively(IFileSystem sourceFs, IFileSystem destFs, string sourcePath, + string destPath) + { + return Result.Success; + } + + public static Result CopyFile(IFileSystem destFs, IFileSystem sourceFs, ReadOnlySpan destParentPath, + ReadOnlySpan sourcePath, ref DirectoryEntry dirEntry, Span copyBuffer) + { + IFile srcFile = null; + IFile dstFile = null; + + try + { + Result rc = sourceFs.OpenFile(out srcFile, sourcePath.FromUtf8Z(), OpenMode.Read); + if (rc.IsFailure()) return rc; + + FsPath dstPath = default; + int dstPathLen = StringUtils.Concat(dstPath.Str, destParentPath); + dstPathLen = StringUtils.Concat(dstPath.Str, dstPathLen, dirEntry.Name); + + if (dstPathLen > FsPath.MaxLength) + { + throw new ArgumentException(); + } + + string dstPathStr = dstPath.Str.FromUtf8Z(); + + rc = destFs.CreateFile(dstPathStr, dirEntry.Size, CreateFileOptions.None); + if (rc.IsFailure()) return rc; + + rc = destFs.OpenFile(out dstFile, dstPathStr, OpenMode.Write); + if (rc.IsFailure()) return rc; + + long fileSize = dirEntry.Size; + long offset = 0; + + while (offset < fileSize) + { + rc = srcFile.Read(out long bytesRead, offset, copyBuffer, ReadOption.None); + if (rc.IsFailure()) return rc; + + rc = dstFile.Write(offset, copyBuffer.Slice(0, (int)bytesRead), WriteOption.None); + if (rc.IsFailure()) return rc; + + offset += bytesRead; + } + + return Result.Success; + } + finally + { + srcFile?.Dispose(); + dstFile?.Dispose(); + } + } + } +} diff --git a/src/LibHac/Fs/FileSystemExtensions.cs b/src/LibHac/Fs/FileSystemExtensions.cs index 50997c48..c55b1498 100644 --- a/src/LibHac/Fs/FileSystemExtensions.cs +++ b/src/LibHac/Fs/FileSystemExtensions.cs @@ -2,33 +2,27 @@ using System.Buffers; using System.Collections.Generic; using System.IO; +using LibHac.Common; namespace LibHac.Fs { public static class FileSystemExtensions { - public static Result CopyDirectory(this IDirectory source, IDirectory dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) + public static Result CopyDirectory(this IFileSystem sourceFs, IFileSystem destFs, string sourcePath, string destPath, + IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) { - IFileSystem sourceFs = source.ParentFileSystem; - IFileSystem destFs = dest.ParentFileSystem; Result rc; - foreach (DirectoryEntry entry in source.Read()) + foreach (DirectoryEntryEx entry in sourceFs.EnumerateEntries()) { - string subSrcPath = PathTools.Normalize(PathTools.Combine(source.FullPath, entry.Name)); - string subDstPath = PathTools.Normalize(PathTools.Combine(dest.FullPath, entry.Name)); + string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); + string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); if (entry.Type == DirectoryEntryType.Directory) { destFs.EnsureDirectoryExists(subDstPath); - rc = sourceFs.OpenDirectory(out IDirectory subSrcDir, subSrcPath, OpenDirectoryMode.All); - if (rc.IsFailure()) return rc; - - rc = destFs.OpenDirectory(out IDirectory subDstDir, subDstPath, OpenDirectoryMode.All); - if (rc.IsFailure()) return rc; - - rc = subSrcDir.CopyDirectory(subDstDir, logger, options); + rc = sourceFs.CopyDirectory(destFs, subSrcPath, subDstPath, logger, options); if (rc.IsFailure()) return rc; } @@ -56,52 +50,45 @@ namespace LibHac.Fs return Result.Success; } - public static void CopyFileSystem(this IFileSystem source, IFileSystem dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) - { - source.OpenDirectory(out IDirectory sourceRoot, "/", OpenDirectoryMode.All).ThrowIfFailure(); - dest.OpenDirectory(out IDirectory destRoot, "/", OpenDirectoryMode.All).ThrowIfFailure(); - - sourceRoot.CopyDirectory(destRoot, logger, options).ThrowIfFailure(); - } - public static void Extract(this IFileSystem source, string destinationPath, IProgressReport logger = null) { var destFs = new LocalFileSystem(destinationPath); - source.CopyFileSystem(destFs, logger); + source.CopyDirectory(destFs, "/", "/", logger); } - public static IEnumerable EnumerateEntries(this IFileSystem fileSystem) + public static IEnumerable EnumerateEntries(this IFileSystem fileSystem) { - return fileSystem.EnumerateEntries("*"); + return fileSystem.EnumerateEntries("/", "*"); } - public static IEnumerable EnumerateEntries(this IFileSystem fileSystem, string searchPattern) + public static IEnumerable EnumerateEntries(this IFileSystem fileSystem, string path, string searchPattern) { - return fileSystem.EnumerateEntries(searchPattern, SearchOptions.RecurseSubdirectories); + return fileSystem.EnumerateEntries(path, searchPattern, SearchOptions.RecurseSubdirectories); } - public static IEnumerable EnumerateEntries(this IFileSystem fileSystem, string searchPattern, SearchOptions searchOptions) + public static IEnumerable EnumerateEntries(this IFileSystem fileSystem, string searchPattern, SearchOptions searchOptions) { - fileSystem.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.All).ThrowIfFailure(); - - return rootDir.EnumerateEntries(searchPattern, searchOptions); + return EnumerateEntries(fileSystem, "/", searchPattern, searchOptions); } - public static IEnumerable EnumerateEntries(this IDirectory directory) - { - return directory.EnumerateEntries("*", SearchOptions.Default); - } - - public static IEnumerable EnumerateEntries(this IDirectory directory, string searchPattern, SearchOptions searchOptions) + public static IEnumerable EnumerateEntries(this IFileSystem fileSystem, string path, string searchPattern, SearchOptions searchOptions) { bool ignoreCase = searchOptions.HasFlag(SearchOptions.CaseInsensitive); bool recurse = searchOptions.HasFlag(SearchOptions.RecurseSubdirectories); - IFileSystem fs = directory.ParentFileSystem; + IFileSystem fs = fileSystem; + DirectoryEntry dirEntry = default; - foreach (DirectoryEntry entry in directory.Read()) + fileSystem.OpenDirectory(out IDirectory directory, path, OpenDirectoryMode.All).ThrowIfFailure(); + + while(true) { + directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry)).ThrowIfFailure(); + if (entriesRead == 0) break; + + DirectoryEntryEx entry = GetDirectoryEntryEx(ref dirEntry, path); + if (PathTools.MatchesPattern(searchPattern, entry.Name, ignoreCase)) { yield return entry; @@ -109,15 +96,28 @@ namespace LibHac.Fs if (entry.Type != DirectoryEntryType.Directory || !recurse) continue; - fs.OpenDirectory(out IDirectory subDir, PathTools.Combine(directory.FullPath, entry.Name), OpenDirectoryMode.All).ThrowIfFailure(); + IEnumerable subEntries = + fs.EnumerateEntries(PathTools.Combine(path, entry.Name), searchPattern, + searchOptions); - foreach (DirectoryEntry subEntry in subDir.EnumerateEntries(searchPattern, searchOptions)) + foreach (DirectoryEntryEx subEntry in subEntries) { yield return subEntry; } } } + private static DirectoryEntryEx GetDirectoryEntryEx(ref DirectoryEntry entry, string parentPath) + { + string name = entry.Name.FromUtf8Z(); + string path = PathTools.Combine(parentPath, name); + + var entryEx = new DirectoryEntryEx(name, path, entry.Type, entry.Size); + entryEx.Attributes = entry.Attributes; + + return entryEx; + } + public static void CopyTo(this IFile file, IFile dest, IProgressReport logger = null) { const int bufferSize = 0x8000; @@ -157,16 +157,14 @@ namespace LibHac.Fs public static int GetEntryCount(this IFileSystem fs, OpenDirectoryMode mode) { - fs.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.All).ThrowIfFailure(); - - return rootDir.GetEntryCountRecursive(mode); + return GetEntryCountRecursive(fs, "/", mode); } - public static int GetEntryCountRecursive(this IDirectory directory, OpenDirectoryMode mode) + public static int GetEntryCountRecursive(this IFileSystem fs, string path, OpenDirectoryMode mode) { int count = 0; - foreach (DirectoryEntry entry in directory.EnumerateEntries()) + foreach (DirectoryEntryEx entry in fs.EnumerateEntries(path, "*")) { if (entry.Type == DirectoryEntryType.Directory && (mode & OpenDirectoryMode.Directory) != 0 || entry.Type == DirectoryEntryType.File && (mode & OpenDirectoryMode.File) != 0) @@ -194,19 +192,17 @@ namespace LibHac.Fs fs.QueryEntry(Span.Empty, Span.Empty, QueryId.MakeConcatFile, path); } - public static void CleanDirectoryRecursivelyGeneric(IDirectory directory) + public static void CleanDirectoryRecursivelyGeneric(IFileSystem fileSystem, string path) { - IFileSystem fs = directory.ParentFileSystem; + IFileSystem fs = fileSystem; - foreach (DirectoryEntry entry in directory.Read()) + foreach (DirectoryEntryEx entry in fileSystem.EnumerateEntries(path, "*")) { - string subPath = PathTools.Combine(directory.FullPath, entry.Name); + string subPath = PathTools.Combine(path, entry.Name); if (entry.Type == DirectoryEntryType.Directory) { - fs.OpenDirectory(out IDirectory subDir, subPath, OpenDirectoryMode.All).ThrowIfFailure(); - - CleanDirectoryRecursivelyGeneric(subDir); + CleanDirectoryRecursivelyGeneric(fileSystem, subPath); fs.DeleteDirectory(subPath); } else if (entry.Type == DirectoryEntryType.File) diff --git a/src/LibHac/Fs/FsPath.cs b/src/LibHac/Fs/FsPath.cs new file mode 100644 index 00000000..7db2b8f0 --- /dev/null +++ b/src/LibHac/Fs/FsPath.cs @@ -0,0 +1,16 @@ +using System; +using System.Runtime.InteropServices; +using LibHac.Common; + +namespace LibHac.Fs +{ + [StructLayout(LayoutKind.Explicit, Size = MaxLength + 1)] + public struct FsPath + { + internal const int MaxLength = 0x300; + + [FieldOffset(0)] private byte _str; + + public Span Str => SpanHelpers.CreateSpan(ref _str, MaxLength + 1); + } +} diff --git a/src/LibHac/Fs/IDirectory.cs b/src/LibHac/Fs/IDirectory.cs index fb214d1a..401d26d7 100644 --- a/src/LibHac/Fs/IDirectory.cs +++ b/src/LibHac/Fs/IDirectory.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System; namespace LibHac.Fs { @@ -8,32 +8,24 @@ namespace LibHac.Fs public interface IDirectory { /// - /// The that contains the current . + /// Retrieves the next entries that this directory contains. Does not search subdirectories. /// - IFileSystem ParentFileSystem { get; } + /// The number of s that + /// were read into . + /// The buffer the entries will be read into. + /// The of the requested operation. + /// With each call of , the object will + /// continue to iterate through all the entries it contains. + /// Each call will attempt to read as many entries as the buffer can contain. + /// Once all the entries have been read, all subsequent calls to will + /// read 0 entries into the buffer. + Result Read(out long entriesRead, Span entryBuffer); /// - /// The full path of the current in its . + /// Retrieves the number of file system entries that this directory contains. Does not search subdirectories. /// - string FullPath { get; } - - /// - /// Specifies which types of entries will be enumerated when is called. - /// - OpenDirectoryMode Mode { get; } - - /// - /// Returns an enumerable collection the file system entries of the types specified by - /// that this directory contains. Does not search subdirectories. - /// - /// An enumerable collection of file system entries in this directory. - IEnumerable Read(); - - /// - /// Returns the number of file system entries of the types specified by - /// that this directory contains. Does not search subdirectories. - /// - /// The number of child entries the directory contains. - int GetEntryCount(); + /// The number of child entries the directory contains. + /// The of the requested operation. + Result GetEntryCount(out long entryCount); } } \ No newline at end of file diff --git a/src/LibHac/Fs/IFileSystem.cs b/src/LibHac/Fs/IFileSystem.cs index 0703baf9..3d99bf3c 100644 --- a/src/LibHac/Fs/IFileSystem.cs +++ b/src/LibHac/Fs/IFileSystem.cs @@ -221,8 +221,9 @@ namespace LibHac.Fs [Flags] public enum OpenDirectoryMode { - Directory = 1, - File = 2, + Directory = 1 << 0, + File = 1 << 1, + NoFileSize = 1 << 31, All = Directory | File } diff --git a/src/LibHac/Fs/LayeredFileSystem.cs b/src/LibHac/Fs/LayeredFileSystem.cs index 500dde46..329f7094 100644 --- a/src/LibHac/Fs/LayeredFileSystem.cs +++ b/src/LibHac/Fs/LayeredFileSystem.cs @@ -38,7 +38,7 @@ namespace LibHac.Fs } } - directory = new LayeredFileSystemDirectory(this, dirs, path, mode); + directory = new LayeredFileSystemDirectory(dirs); return Result.Success; } diff --git a/src/LibHac/Fs/LayeredFileSystemDirectory.cs b/src/LibHac/Fs/LayeredFileSystemDirectory.cs index ee980bc4..9d1e31dc 100644 --- a/src/LibHac/Fs/LayeredFileSystemDirectory.cs +++ b/src/LibHac/Fs/LayeredFileSystemDirectory.cs @@ -1,44 +1,51 @@ -using System.Collections.Generic; -using System.Linq; +using System; +using System.Collections.Generic; namespace LibHac.Fs { public class LayeredFileSystemDirectory : IDirectory { - public IFileSystem ParentFileSystem { get; } - - public string FullPath { get; } - public OpenDirectoryMode Mode { get; } - private List Sources { get; } - public LayeredFileSystemDirectory(IFileSystem fs, List sources, string path, OpenDirectoryMode mode) + public LayeredFileSystemDirectory(List sources) { - ParentFileSystem = fs; Sources = sources; - FullPath = path; - Mode = mode; } - public IEnumerable Read() + // Todo: Don't return duplicate entries + public Result Read(out long entriesRead, Span entryBuffer) { - var returnedFiles = new HashSet(); + entriesRead = 0; + int entryIndex = 0; - foreach (IDirectory source in Sources) + for (int i = 0; i < Sources.Count && entryIndex < entryBuffer.Length; i++) { - foreach (DirectoryEntry entry in source.Read()) - { - if (returnedFiles.Contains(entry.FullPath)) continue; + Result rs = Sources[i].Read(out long subEntriesRead, entryBuffer.Slice(entryIndex)); + if (rs.IsFailure()) return rs; - returnedFiles.Add(entry.FullPath); - yield return entry; - } + entryIndex += (int)subEntriesRead; } + + entriesRead = entryIndex; + return Result.Success; } - public int GetEntryCount() + // Todo: Don't count duplicate entries + public Result GetEntryCount(out long entryCount) { - return Read().Count(); + entryCount = 0; + long totalEntryCount = 0; + + foreach (IDirectory dir in Sources) + { + Result rc = dir.GetEntryCount(out long subEntryCount); + if (rc.IsFailure()) return rc; + + totalEntryCount += subEntryCount; + } + + entryCount = totalEntryCount; + return Result.Success; } } } diff --git a/src/LibHac/Fs/LocalDirectory.cs b/src/LibHac/Fs/LocalDirectory.cs index 3086be3b..bbce488d 100644 --- a/src/LibHac/Fs/LocalDirectory.cs +++ b/src/LibHac/Fs/LocalDirectory.cs @@ -2,22 +2,19 @@ using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; +using LibHac.Common; namespace LibHac.Fs { public class LocalDirectory : IDirectory { - public IFileSystem ParentFileSystem { get; } - public string FullPath { get; } - private string LocalPath { get; } - public OpenDirectoryMode Mode { get; } + private OpenDirectoryMode Mode { get; } private DirectoryInfo DirInfo { get; } + private IEnumerator EntryEnumerator { get; } public LocalDirectory(LocalFileSystem fs, string path, OpenDirectoryMode mode) { - ParentFileSystem = fs; - FullPath = path; LocalPath = fs.ResolveLocalPath(path); Mode = mode; @@ -36,27 +33,42 @@ namespace LibHac.Fs { ThrowHelper.ThrowResult(ResultFs.PathNotFound); } + + EntryEnumerator = DirInfo.EnumerateFileSystemInfos().GetEnumerator(); } - public IEnumerable Read() + public Result Read(out long entriesRead, Span entryBuffer) { - foreach (FileSystemInfo entry in DirInfo.EnumerateFileSystemInfos()) + int i = 0; + + while (i < entryBuffer.Length && EntryEnumerator.MoveNext()) { - bool isDir = (entry.Attributes & FileAttributes.Directory) != 0; + FileSystemInfo localEntry = EntryEnumerator.Current; + if (localEntry == null) break; + + bool isDir = localEntry.Attributes.HasFlag(FileAttributes.Directory); if (!CanReturnEntry(isDir, Mode)) continue; + ReadOnlySpan name = Util.GetUtf8Bytes(localEntry.Name); DirectoryEntryType type = isDir ? DirectoryEntryType.Directory : DirectoryEntryType.File; - long length = isDir ? 0 : ((FileInfo)entry).Length; + long length = isDir ? 0 : ((FileInfo)localEntry).Length; - yield return new DirectoryEntry(entry.Name, PathTools.Combine(FullPath, entry.Name), type, length) - { - Attributes = entry.Attributes.ToNxAttributes() - }; + StringUtils.Copy(entryBuffer[i].Name, name); + entryBuffer[i].Name[PathTools.MaxPathLength] = 0; + + entryBuffer[i].Attributes = localEntry.Attributes.ToNxAttributes(); + entryBuffer[i].Type = type; + entryBuffer[i].Size = length; + + i++; } + + entriesRead = i; + return Result.Success; } - public int GetEntryCount() + public Result GetEntryCount(out long entryCount) { int count = 0; @@ -67,7 +79,8 @@ namespace LibHac.Fs if (CanReturnEntry(isDir, Mode)) count++; } - return count; + entryCount = count; + return Result.Success; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/LibHac/Fs/PartitionDirectory.cs b/src/LibHac/Fs/PartitionDirectory.cs index dc6e4db1..4f8feaba 100644 --- a/src/LibHac/Fs/PartitionDirectory.cs +++ b/src/LibHac/Fs/PartitionDirectory.cs @@ -1,15 +1,15 @@ -using System.Collections.Generic; +using System; using System.IO; +using System.Text; +using LibHac.Common; namespace LibHac.Fs { public class PartitionDirectory : IDirectory { - IFileSystem IDirectory.ParentFileSystem => ParentFileSystem; - public PartitionFileSystem ParentFileSystem { get; } - public string FullPath { get; } - - public OpenDirectoryMode Mode { get; } + private PartitionFileSystem ParentFileSystem { get; } + private OpenDirectoryMode Mode { get; } + private int CurrentIndex { get; set; } public PartitionDirectory(PartitionFileSystem fs, string path, OpenDirectoryMode mode) { @@ -18,23 +18,43 @@ namespace LibHac.Fs if (path != "/") throw new DirectoryNotFoundException(); ParentFileSystem = fs; - FullPath = path; Mode = mode; + + CurrentIndex = 0; } - - public IEnumerable Read() + public Result Read(out long entriesRead, Span entryBuffer) { - if (Mode.HasFlag(OpenDirectoryMode.File)) + if (!Mode.HasFlag(OpenDirectoryMode.File)) { - foreach (PartitionFileEntry entry in ParentFileSystem.Files) - { - yield return new DirectoryEntry(entry.Name, '/' + entry.Name, DirectoryEntryType.File, entry.Size); - } + entriesRead = 0; + return Result.Success; } + + int entriesRemaining = ParentFileSystem.Files.Length - CurrentIndex; + int toRead = Math.Min(entriesRemaining, entryBuffer.Length); + + for (int i = 0; i < toRead; i++) + { + PartitionFileEntry fileEntry = ParentFileSystem.Files[CurrentIndex]; + ref DirectoryEntry entry = ref entryBuffer[i]; + + Span nameUtf8 = Encoding.UTF8.GetBytes(fileEntry.Name); + + entry.Type = DirectoryEntryType.File; + entry.Size = fileEntry.Size; + + StringUtils.Copy(entry.Name, nameUtf8); + entry.Name[PathTools.MaxPathLength] = 0; + + CurrentIndex++; + } + + entriesRead = toRead; + return Result.Success; } - public int GetEntryCount() + public Result GetEntryCount(out long entryCount) { int count = 0; @@ -43,7 +63,8 @@ namespace LibHac.Fs count += ParentFileSystem.Files.Length; } - return count; + entryCount = count; + return Result.Success; } } } \ No newline at end of file diff --git a/src/LibHac/Fs/PartitionFileSystemBuilder.cs b/src/LibHac/Fs/PartitionFileSystemBuilder.cs index 9a41c18d..853ae77a 100644 --- a/src/LibHac/Fs/PartitionFileSystemBuilder.cs +++ b/src/LibHac/Fs/PartitionFileSystemBuilder.cs @@ -22,9 +22,7 @@ namespace LibHac.Fs /// public PartitionFileSystemBuilder(IFileSystem input) { - input.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.File).ThrowIfFailure(); - - foreach (DirectoryEntry entry in rootDir.Read().OrderBy(x => x.FullPath, StringComparer.Ordinal)) + foreach (DirectoryEntryEx entry in input.EnumerateEntries().OrderBy(x => x.FullPath, StringComparer.Ordinal)) { input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure(); diff --git a/src/LibHac/Fs/PathTools.cs b/src/LibHac/Fs/PathTools.cs index 538bd218..d5ad17f8 100644 --- a/src/LibHac/Fs/PathTools.cs +++ b/src/LibHac/Fs/PathTools.cs @@ -13,6 +13,8 @@ namespace LibHac.Fs public static readonly char DirectorySeparator = '/'; public static readonly char MountSeparator = ':'; internal const int MountNameLength = 0xF; + + // Todo: Remove internal const int MaxPathLength = 0x300; public static string Normalize(string inPath) diff --git a/src/LibHac/Fs/ReadOnlyDirectory.cs b/src/LibHac/Fs/ReadOnlyDirectory.cs deleted file mode 100644 index 5d8a3c27..00000000 --- a/src/LibHac/Fs/ReadOnlyDirectory.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace LibHac.Fs -{ - public class ReadOnlyDirectory : IDirectory - { - private IDirectory BaseDir { get; } - public IFileSystem ParentFileSystem { get; } - - public string FullPath => BaseDir.FullPath; - public OpenDirectoryMode Mode => BaseDir.Mode; - - public ReadOnlyDirectory(IFileSystem parentFileSystem, IDirectory baseDirectory) - { - ParentFileSystem = parentFileSystem; - BaseDir = baseDirectory; - } - - public IEnumerable Read() => BaseDir.Read(); - public int GetEntryCount() => BaseDir.GetEntryCount(); - } -} diff --git a/src/LibHac/Fs/ReadOnlyFileSystem.cs b/src/LibHac/Fs/ReadOnlyFileSystem.cs index 417b2526..a4fc43d7 100644 --- a/src/LibHac/Fs/ReadOnlyFileSystem.cs +++ b/src/LibHac/Fs/ReadOnlyFileSystem.cs @@ -13,13 +13,7 @@ namespace LibHac.Fs public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { - directory = default; - - Result rc = BaseFs.OpenDirectory(out IDirectory baseDir, path, mode); - if (rc.IsFailure()) return rc; - - directory = new ReadOnlyDirectory(this, baseDir); - return Result.Success; + return BaseFs.OpenDirectory(out directory, path, mode); } public Result OpenFile(out IFile file, string path, OpenMode mode) diff --git a/src/LibHac/Fs/RomFs/RomFsBuilder.cs b/src/LibHac/Fs/RomFs/RomFsBuilder.cs index 055e2c4f..c4ab96d8 100644 --- a/src/LibHac/Fs/RomFs/RomFsBuilder.cs +++ b/src/LibHac/Fs/RomFs/RomFsBuilder.cs @@ -32,7 +32,7 @@ namespace LibHac.Fs.RomFs /// public RomFsBuilder(IFileSystem input) { - foreach (DirectoryEntry entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File) + foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File) .OrderBy(x => x.FullPath, StringComparer.Ordinal)) { input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure(); diff --git a/src/LibHac/Fs/RomFs/RomFsDirectory.cs b/src/LibHac/Fs/RomFs/RomFsDirectory.cs index 3b8cb119..7b39248c 100644 --- a/src/LibHac/Fs/RomFs/RomFsDirectory.cs +++ b/src/LibHac/Fs/RomFs/RomFsDirectory.cs @@ -1,71 +1,87 @@ -using System.Collections.Generic; +using System; +using System.Text; +using LibHac.Common; namespace LibHac.Fs.RomFs { public class RomFsDirectory : IDirectory { - IFileSystem IDirectory.ParentFileSystem => ParentFileSystem; - public RomFsFileSystem ParentFileSystem { get; } - public string FullPath { get; } + private RomFsFileSystem ParentFileSystem { get; } - public OpenDirectoryMode Mode { get; } + private OpenDirectoryMode Mode { get; } private FindPosition InitialPosition { get; } + private FindPosition _currentPosition; - public RomFsDirectory(RomFsFileSystem fs, string path, FindPosition position, OpenDirectoryMode mode) + public RomFsDirectory(RomFsFileSystem fs, FindPosition position, OpenDirectoryMode mode) { ParentFileSystem = fs; InitialPosition = position; - FullPath = path; + _currentPosition = position; Mode = mode; } - public IEnumerable Read() + public Result Read(out long entriesRead, Span entryBuffer) { - FindPosition position = InitialPosition; - HierarchicalRomFileTable tab = ParentFileSystem.FileTable; - - if (Mode.HasFlag(OpenDirectoryMode.Directory)) - { - while (tab.FindNextDirectory(ref position, out string name)) - { - yield return new DirectoryEntry(name, PathTools.Combine(FullPath, name), DirectoryEntryType.Directory, 0); - } - } - - if (Mode.HasFlag(OpenDirectoryMode.File)) - { - while (tab.FindNextFile(ref position, out RomFileInfo info, out string name)) - { - yield return new DirectoryEntry(name, PathTools.Combine(FullPath, name), DirectoryEntryType.File, info.Length); - } - } + return ReadImpl(out entriesRead, ref _currentPosition, entryBuffer); } - public int GetEntryCount() + public Result GetEntryCount(out long entryCount) { - int count = 0; - FindPosition position = InitialPosition; + + return ReadImpl(out entryCount, ref position, Span.Empty); + } + + private Result ReadImpl(out long entriesRead, ref FindPosition position, Span entryBuffer) + { HierarchicalRomFileTable tab = ParentFileSystem.FileTable; + int i = 0; + if (Mode.HasFlag(OpenDirectoryMode.Directory)) { - while (tab.FindNextDirectory(ref position, out string _)) + while ((entryBuffer.IsEmpty || i < entryBuffer.Length) && tab.FindNextDirectory(ref position, out string name)) { - count++; + if (!entryBuffer.IsEmpty) + { + ref DirectoryEntry entry = ref entryBuffer[i]; + Span nameUtf8 = Encoding.UTF8.GetBytes(name); + + StringUtils.Copy(entry.Name, nameUtf8); + entry.Name[PathTools.MaxPathLength] = 0; + + entry.Type = DirectoryEntryType.Directory; + entry.Size = 0; + } + + i++; } } if (Mode.HasFlag(OpenDirectoryMode.File)) { - while (tab.FindNextFile(ref position, out RomFileInfo _, out string _)) + while ((entryBuffer.IsEmpty || i < entryBuffer.Length) && tab.FindNextFile(ref position, out RomFileInfo info, out string name)) { - count++; + if (!entryBuffer.IsEmpty) + { + ref DirectoryEntry entry = ref entryBuffer[i]; + Span nameUtf8 = Encoding.UTF8.GetBytes(name); + + StringUtils.Copy(entry.Name, nameUtf8); + entry.Name[PathTools.MaxPathLength] = 0; + + entry.Type = DirectoryEntryType.File; + entry.Size = info.Length; + } + + i++; } } - return count; + entriesRead = i; + + return Result.Success; } } } diff --git a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs index 0b9970a4..4651a177 100644 --- a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs @@ -57,7 +57,7 @@ namespace LibHac.Fs.RomFs return ResultFs.PathNotFound.Log(); } - directory = new RomFsDirectory(this, path, position, mode); + directory = new RomFsDirectory(this, position, mode); return Result.Success; } diff --git a/src/LibHac/Fs/Save/SaveDataDirectory.cs b/src/LibHac/Fs/Save/SaveDataDirectory.cs index b2fe7fd3..c4a73343 100644 --- a/src/LibHac/Fs/Save/SaveDataDirectory.cs +++ b/src/LibHac/Fs/Save/SaveDataDirectory.cs @@ -1,71 +1,87 @@ -using System.Collections.Generic; +using System; +using System.Text; +using LibHac.Common; namespace LibHac.Fs.Save { public class SaveDataDirectory : IDirectory { - IFileSystem IDirectory.ParentFileSystem => ParentFileSystem; - public SaveDataFileSystemCore ParentFileSystem { get; } - public string FullPath { get; } + private SaveDataFileSystemCore ParentFileSystem { get; } - public OpenDirectoryMode Mode { get; } + private OpenDirectoryMode Mode { get; } private SaveFindPosition InitialPosition { get; } + private SaveFindPosition _currentPosition; - public SaveDataDirectory(SaveDataFileSystemCore fs, string path, SaveFindPosition position, OpenDirectoryMode mode) + public SaveDataDirectory(SaveDataFileSystemCore fs, SaveFindPosition position, OpenDirectoryMode mode) { ParentFileSystem = fs; InitialPosition = position; - FullPath = path; + _currentPosition = position; Mode = mode; } - public IEnumerable Read() + public Result Read(out long entriesRead, Span entryBuffer) { - SaveFindPosition position = InitialPosition; - HierarchicalSaveFileTable tab = ParentFileSystem.FileTable; - - if (Mode.HasFlag(OpenDirectoryMode.Directory)) - { - while (tab.FindNextDirectory(ref position, out string name)) - { - yield return new DirectoryEntry(name, PathTools.Combine(FullPath, name), DirectoryEntryType.Directory, 0); - } - } - - if (Mode.HasFlag(OpenDirectoryMode.File)) - { - while (tab.FindNextFile(ref position, out SaveFileInfo info, out string name)) - { - yield return new DirectoryEntry(name, PathTools.Combine(FullPath, name), DirectoryEntryType.File, info.Length); - } - } + return ReadImpl(out entriesRead, ref _currentPosition, entryBuffer); } - public int GetEntryCount() + public Result GetEntryCount(out long entryCount) { - int count = 0; - SaveFindPosition position = InitialPosition; + + return ReadImpl(out entryCount, ref position, Span.Empty); + } + + private Result ReadImpl(out long entriesRead, ref SaveFindPosition position, Span entryBuffer) + { HierarchicalSaveFileTable tab = ParentFileSystem.FileTable; + int i = 0; + if (Mode.HasFlag(OpenDirectoryMode.Directory)) { - while (tab.FindNextDirectory(ref position, out string _)) + while ((entryBuffer.IsEmpty || i < entryBuffer.Length) && tab.FindNextDirectory(ref position, out string name)) { - count++; + if (!entryBuffer.IsEmpty) + { + ref DirectoryEntry entry = ref entryBuffer[i]; + Span nameUtf8 = Encoding.UTF8.GetBytes(name); + + StringUtils.Copy(entry.Name, nameUtf8); + entry.Name[64] = 0; + + entry.Type = DirectoryEntryType.Directory; + entry.Size = 0; + } + + i++; } } if (Mode.HasFlag(OpenDirectoryMode.File)) { - while (tab.FindNextFile(ref position, out SaveFileInfo _, out string _)) + while ((entryBuffer.IsEmpty || i < entryBuffer.Length) && tab.FindNextFile(ref position, out SaveFileInfo info, out string name)) { - count++; + if (!entryBuffer.IsEmpty) + { + ref DirectoryEntry entry = ref entryBuffer[i]; + Span nameUtf8 = Encoding.UTF8.GetBytes(name); + + StringUtils.Copy(entry.Name, nameUtf8); + entry.Name[64] = 0; + + entry.Type = DirectoryEntryType.File; + entry.Size = info.Length; + } + + i++; } } - return count; + entriesRead = i; + + return Result.Success; } } } diff --git a/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs b/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs index 721fe75b..c408a325 100644 --- a/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs +++ b/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs @@ -88,10 +88,7 @@ namespace LibHac.Fs.Save { path = PathTools.Normalize(path); - Result rc = OpenDirectory(out IDirectory dir, path, OpenDirectoryMode.All); - if (rc.IsFailure()) return rc; - - FileSystemExtensions.CleanDirectoryRecursivelyGeneric(dir); + FileSystemExtensions.CleanDirectoryRecursivelyGeneric(this, path); return Result.Success; } @@ -125,7 +122,7 @@ namespace LibHac.Fs.Save return ResultFs.PathNotFound.Log(); } - directory = new SaveDataDirectory(this, path, position, mode); + directory = new SaveDataDirectory(this, position, mode); return Result.Success; } @@ -223,7 +220,7 @@ namespace LibHac.Fs.Save { AllocationTable.FsTrim(); - foreach (DirectoryEntry file in this.EnumerateEntries("*", SearchOptions.RecurseSubdirectories)) + foreach (DirectoryEntryEx file in this.EnumerateEntries("*", SearchOptions.RecurseSubdirectories)) { if (FileTable.TryOpenFile(file.FullPath, out SaveFileInfo fileInfo) && fileInfo.StartBlock >= 0) { diff --git a/src/LibHac/Fs/SubdirectoryFileSystem.cs b/src/LibHac/Fs/SubdirectoryFileSystem.cs index 57f80d1a..b5fabd41 100644 --- a/src/LibHac/Fs/SubdirectoryFileSystem.cs +++ b/src/LibHac/Fs/SubdirectoryFileSystem.cs @@ -64,10 +64,7 @@ namespace LibHac.Fs { path = PathTools.Normalize(path); - ParentFileSystem.OpenDirectory(out IDirectory baseDir, ResolveFullPath(path), mode); - - directory = new SubdirectoryFileSystemDirectory(this, baseDir, path, mode); - return Result.Success; + return ParentFileSystem.OpenDirectory(out directory, ResolveFullPath(path), mode); } public Result OpenFile(out IFile file, string path, OpenMode mode) diff --git a/src/LibHac/Fs/SubdirectoryFileSystemDirectory.cs b/src/LibHac/Fs/SubdirectoryFileSystemDirectory.cs deleted file mode 100644 index cc2762d6..00000000 --- a/src/LibHac/Fs/SubdirectoryFileSystemDirectory.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; - -namespace LibHac.Fs -{ - public class SubdirectoryFileSystemDirectory : IDirectory - { - public SubdirectoryFileSystemDirectory(SubdirectoryFileSystem fs, IDirectory baseDir, string path, OpenDirectoryMode mode) - { - ParentFileSystem = fs; - BaseDirectory = baseDir; - FullPath = path; - Mode = mode; - } - - public IFileSystem ParentFileSystem { get; } - public string FullPath { get; } - public OpenDirectoryMode Mode { get; } - - private IDirectory BaseDirectory { get; } - - public IEnumerable Read() - { - foreach (DirectoryEntry entry in BaseDirectory.Read()) - { - yield return new DirectoryEntry(entry.Name, PathTools.Combine(FullPath, entry.Name), entry.Type, entry.Size); - } - } - - public int GetEntryCount() - { - return BaseDirectory.GetEntryCount(); - } - } -} diff --git a/src/LibHac/FsClient/Accessors/DirectoryAccessor.cs b/src/LibHac/FsClient/Accessors/DirectoryAccessor.cs index 94df1121..86eed8ed 100644 --- a/src/LibHac/FsClient/Accessors/DirectoryAccessor.cs +++ b/src/LibHac/FsClient/Accessors/DirectoryAccessor.cs @@ -10,24 +10,34 @@ namespace LibHac.FsClient.Accessors public FileSystemAccessor Parent { get; } - public DirectoryAccessor(IDirectory baseDirectory, FileSystemAccessor parent) + private IFileSystem ParentFs { get; } + private string Path { get; } + + public DirectoryAccessor(IDirectory baseDirectory, FileSystemAccessor parent, IFileSystem parentFs, string path) { Directory = baseDirectory; Parent = parent; + ParentFs = parentFs; + Path = path; } - public IEnumerable Read() + public IEnumerable Read() { CheckIfDisposed(); - return Directory.Read(); + return ParentFs.EnumerateEntries(Path, "*", SearchOptions.Default); } - public int GetEntryCount() + public Result Read(out long entriesRead, Span entryBuffer) + { + return Directory.Read(out entriesRead, entryBuffer); + } + + public Result GetEntryCount(out long entryCount) { CheckIfDisposed(); - return Directory.GetEntryCount(); + return Directory.GetEntryCount(out entryCount); } public void Dispose() diff --git a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs index 317e7dd0..8916322b 100644 --- a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs +++ b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs @@ -63,7 +63,7 @@ namespace LibHac.FsClient.Accessors Result rc = FileSystem.OpenDirectory(out IDirectory rawDirectory, path, mode); if (rc.IsFailure()) return rc; - var accessor = new DirectoryAccessor(rawDirectory, this); + var accessor = new DirectoryAccessor(rawDirectory, this, FileSystem, path); lock (_locker) { diff --git a/src/LibHac/FsClient/FileSystemClient.Directory.cs b/src/LibHac/FsClient/FileSystemClient.Directory.cs index e72d67c2..4395e55d 100644 --- a/src/LibHac/FsClient/FileSystemClient.Directory.cs +++ b/src/LibHac/FsClient/FileSystemClient.Directory.cs @@ -12,7 +12,7 @@ namespace LibHac.FsClient } // todo: change to not use IEnumerable - public IEnumerable ReadDirectory(DirectoryHandle handle) + public IEnumerable ReadDirectory(DirectoryHandle handle) { throw new NotImplementedException(); } diff --git a/src/LibHac/FsClient/FileSystemManager.cs b/src/LibHac/FsClient/FileSystemManager.cs index 08d87565..87d442ce 100644 --- a/src/LibHac/FsClient/FileSystemManager.cs +++ b/src/LibHac/FsClient/FileSystemManager.cs @@ -509,17 +509,15 @@ namespace LibHac.FsClient // ========================== public Result GetDirectoryEntryCount(out long count, DirectoryHandle handle) { - count = handle.Directory.GetEntryCount(); - - return Result.Success; + return handle.Directory.GetEntryCount(out count); } - public IEnumerable ReadDirectory(DirectoryHandle handle) + public IEnumerable ReadDirectory(DirectoryHandle handle) { if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - IEnumerable entries = handle.Directory.Read(); + IEnumerable entries = handle.Directory.Read(); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); @@ -529,6 +527,26 @@ namespace LibHac.FsClient return handle.Directory.Read(); } + public Result ReadDirectory2(out long entriesRead, Span entryBuffer, DirectoryHandle handle) + { + Result rc; + + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) + { + TimeSpan startTime = Time.GetCurrent(); + rc = handle.Directory.Read(out entriesRead, entryBuffer); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, handle, string.Empty); + } + else + { + rc = handle.Directory.Read(out entriesRead, entryBuffer); + } + + return rc; + } + public void CloseDirectory(DirectoryHandle handle) { if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) diff --git a/src/LibHac/FsClient/FileSystemManagerUtils.cs b/src/LibHac/FsClient/FileSystemManagerUtils.cs index 31d6fe55..af9bf0a6 100644 --- a/src/LibHac/FsClient/FileSystemManagerUtils.cs +++ b/src/LibHac/FsClient/FileSystemManagerUtils.cs @@ -16,7 +16,7 @@ namespace LibHac.FsClient using (sourceHandle) { - foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) + foreach (DirectoryEntryEx entry in fs.ReadDirectory(sourceHandle)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); @@ -95,17 +95,17 @@ namespace LibHac.FsClient return Result.Success; } - public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path) + public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path) { return fs.EnumerateEntries(path, "*"); } - public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path, string searchPattern) + public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path, string searchPattern) { return fs.EnumerateEntries(path, searchPattern, SearchOptions.RecurseSubdirectories); } - public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path, string searchPattern, SearchOptions searchOptions) + public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path, string searchPattern, SearchOptions searchOptions) { bool ignoreCase = searchOptions.HasFlag(SearchOptions.CaseInsensitive); bool recurse = searchOptions.HasFlag(SearchOptions.RecurseSubdirectories); @@ -114,7 +114,7 @@ namespace LibHac.FsClient using (sourceHandle) { - foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) + foreach (DirectoryEntryEx entry in fs.ReadDirectory(sourceHandle)) { if (PathTools.MatchesPattern(searchPattern, entry.Name, ignoreCase)) { @@ -125,9 +125,9 @@ namespace LibHac.FsClient string subPath = PathTools.Normalize(PathTools.Combine(path, entry.Name)); - IEnumerable subEntries = fs.EnumerateEntries(subPath, searchPattern, searchOptions); + IEnumerable subEntries = fs.EnumerateEntries(subPath, searchPattern, searchOptions); - foreach (DirectoryEntry subEntry in subEntries) + foreach (DirectoryEntryEx subEntry in subEntries) { subEntry.FullPath = PathTools.Combine(path, subEntry.Name); yield return subEntry; diff --git a/src/LibHac/LibHac.csproj b/src/LibHac/LibHac.csproj index 7091ca5c..c1033804 100644 --- a/src/LibHac/LibHac.csproj +++ b/src/LibHac/LibHac.csproj @@ -23,6 +23,7 @@ true $(NoWarn);1591;NU5105 true + true diff --git a/src/LibHac/SwitchFs.cs b/src/LibHac/SwitchFs.cs index 2f91685c..f87b879a 100644 --- a/src/LibHac/SwitchFs.cs +++ b/src/LibHac/SwitchFs.cs @@ -67,13 +67,11 @@ namespace LibHac private void OpenAllNcas() { - ContentFs.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.All).ThrowIfFailure(); - // Todo: give warning if directories named "*.nca" are found or manually fix the archive bit - IEnumerable files = rootDir.EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories) + IEnumerable files = ContentFs.EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories) .Where(x => x.Type == DirectoryEntryType.File); - foreach (DirectoryEntry fileEntry in files) + foreach (DirectoryEntryEx fileEntry in files) { SwitchFsNca nca = null; try @@ -109,7 +107,7 @@ namespace LibHac { if (SaveFs == null) return; - foreach (DirectoryEntry fileEntry in SaveFs.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)) + foreach (DirectoryEntryEx fileEntry in SaveFs.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)) { SaveDataFileSystem save = null; string saveName = Path.GetFileNameWithoutExtension(fileEntry.Name); @@ -141,7 +139,7 @@ namespace LibHac var title = new Title(); IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - string cnmtPath = fs.EnumerateEntries("*.cnmt").Single().FullPath; + string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; fs.OpenFile(out IFile file, cnmtPath, OpenMode.Read).ThrowIfFailure(); diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index 0e3d2c1b..1614a723 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -30,7 +30,7 @@ namespace hactoolnet using (sourceHandle) { - foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) + foreach (DirectoryEntryEx entry in fs.ReadDirectory(sourceHandle)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); @@ -57,7 +57,7 @@ namespace hactoolnet { long size = 0; - foreach (DirectoryEntry entry in fs.EnumerateEntries(path, searchPattern)) + foreach (DirectoryEntryEx entry in fs.EnumerateEntries(path, searchPattern)) { size += entry.Size; } diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index 5b301917..73b94ce9 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -73,7 +73,7 @@ namespace hactoolnet { IFileSystem romfs = OpenFileSystemByType(NcaSectionType.Data); - foreach (DirectoryEntry entry in romfs.EnumerateEntries()) + foreach (DirectoryEntryEx entry in romfs.EnumerateEntries()) { ctx.Logger.LogMessage(entry.FullPath); } diff --git a/src/hactoolnet/ProcessRomfs.cs b/src/hactoolnet/ProcessRomfs.cs index ac16b8df..950b757a 100644 --- a/src/hactoolnet/ProcessRomfs.cs +++ b/src/hactoolnet/ProcessRomfs.cs @@ -20,7 +20,7 @@ namespace hactoolnet if (ctx.Options.ListRomFs) { - foreach (DirectoryEntry entry in romfs.EnumerateEntries()) + foreach (DirectoryEntryEx entry in romfs.EnumerateEntries()) { ctx.Logger.LogMessage(entry.FullPath); } diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index e95f8340..ae1b7d6b 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -131,7 +131,7 @@ namespace hactoolnet if (ctx.Options.ListFiles) { - foreach (DirectoryEntry entry in save.EnumerateEntries()) + foreach (DirectoryEntryEx entry in save.EnumerateEntries()) { ctx.Logger.LogMessage(entry.FullPath); } @@ -228,7 +228,7 @@ namespace hactoolnet { var sb = new StringBuilder(); - foreach (DirectoryEntry entry in save.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)) + foreach (DirectoryEntryEx entry in save.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)) { save.FileTable.TryOpenFile(entry.FullPath, out SaveFileInfo fileInfo); if (fileInfo.StartBlock < 0) continue; diff --git a/src/hactoolnet/ProcessSwitchFs.cs b/src/hactoolnet/ProcessSwitchFs.cs index 35ead159..9dfc8ba9 100644 --- a/src/hactoolnet/ProcessSwitchFs.cs +++ b/src/hactoolnet/ProcessSwitchFs.cs @@ -316,7 +316,7 @@ namespace hactoolnet IFileSystem fs = switchFs.ContentFs; - DirectoryEntry[] ncaDirs = fs.EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories) + DirectoryEntryEx[] ncaDirs = fs.EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories) .Where(x => x.Type == DirectoryEntryType.Directory) .Where(x => fs.FileExists($"{x.FullPath}/00")) .ToArray(); @@ -326,7 +326,7 @@ namespace hactoolnet ctx.Logger.LogMessage("Warning: NCA folders without the archive flag were found. Fixing..."); } - foreach (DirectoryEntry file in ncaDirs) + foreach (DirectoryEntryEx file in ncaDirs) { fs.SetConcatenationFileAttribute(file.FullPath); ctx.Logger.LogMessage($"{file.FullPath}"); From 2f490214058e79631bee5f40a1aefb76e6665355 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 15 Sep 2019 08:11:54 -0500 Subject: [PATCH 15/46] Begin filling out FileSystemClient functions --- src/LibHac/Fs/FileSystemExtensions.cs | 4 +- .../FsClient/FileSystemClient.Directory.cs | 10 ++--- src/LibHac/FsClient/FileSystemClient.File.cs | 24 ++++++------ .../FsClient/FileSystemClient.FileSystem.cs | 35 ++++++++--------- src/LibHac/FsClient/FileSystemManager.cs | 39 +++++++++---------- src/LibHac/FsClient/FileSystemManagerUtils.cs | 19 ++++++--- src/hactoolnet/FsUtils.cs | 4 +- 7 files changed, 69 insertions(+), 66 deletions(-) diff --git a/src/LibHac/Fs/FileSystemExtensions.cs b/src/LibHac/Fs/FileSystemExtensions.cs index c55b1498..5fca64dd 100644 --- a/src/LibHac/Fs/FileSystemExtensions.cs +++ b/src/LibHac/Fs/FileSystemExtensions.cs @@ -13,7 +13,7 @@ namespace LibHac.Fs { Result rc; - foreach (DirectoryEntryEx entry in sourceFs.EnumerateEntries()) + foreach (DirectoryEntryEx entry in sourceFs.EnumerateEntries(sourcePath, "*", SearchOptions.Default)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); @@ -107,7 +107,7 @@ namespace LibHac.Fs } } - private static DirectoryEntryEx GetDirectoryEntryEx(ref DirectoryEntry entry, string parentPath) + internal static DirectoryEntryEx GetDirectoryEntryEx(ref DirectoryEntry entry, string parentPath) { string name = entry.Name.FromUtf8Z(); string path = PathTools.Combine(parentPath, name); diff --git a/src/LibHac/FsClient/FileSystemClient.Directory.cs b/src/LibHac/FsClient/FileSystemClient.Directory.cs index 4395e55d..61b9151d 100644 --- a/src/LibHac/FsClient/FileSystemClient.Directory.cs +++ b/src/LibHac/FsClient/FileSystemClient.Directory.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using LibHac.Fs; namespace LibHac.FsClient @@ -8,18 +7,17 @@ namespace LibHac.FsClient { public Result GetDirectoryEntryCount(out long count, DirectoryHandle handle) { - throw new NotImplementedException(); + return FsManager.GetDirectoryEntryCount(out count, handle); } - // todo: change to not use IEnumerable - public IEnumerable ReadDirectory(DirectoryHandle handle) + public Result ReadDirectory(out long entriesRead, Span entryBuffer, DirectoryHandle handle) { - throw new NotImplementedException(); + return FsManager.ReadDirectory(out entriesRead, entryBuffer, handle); } public void CloseDirectory(DirectoryHandle handle) { - throw new NotImplementedException(); + FsManager.CloseDirectory(handle); } } } diff --git a/src/LibHac/FsClient/FileSystemClient.File.cs b/src/LibHac/FsClient/FileSystemClient.File.cs index b4b13a0f..51a6b4dd 100644 --- a/src/LibHac/FsClient/FileSystemClient.File.cs +++ b/src/LibHac/FsClient/FileSystemClient.File.cs @@ -7,52 +7,52 @@ namespace LibHac.FsClient { public Result ReadFile(FileHandle handle, long offset, Span destination) { - throw new NotImplementedException(); + return FsManager.ReadFile(handle, offset, destination); } public Result ReadFile(FileHandle handle, long offset, Span destination, ReadOption options) { - throw new NotImplementedException(); + return FsManager.ReadFile(handle, offset, destination, options); } public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination) { - throw new NotImplementedException(); + return FsManager.ReadFile(out bytesRead, handle, offset, destination); } public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination, ReadOption options) { - throw new NotImplementedException(); + return FsManager.ReadFile(out bytesRead, handle, offset, destination, options); } - public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source, WriteOption options) + public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source, WriteOption options) { - throw new NotImplementedException(); + return FsManager.WriteFile(handle, source, offset, options); } public Result FlushFile(FileHandle handle) { - throw new NotImplementedException(); + return FsManager.FlushFile(handle); } - public Result GetFileSize(out long size, FileHandle handle) + public Result GetFileSize(out long fileSize, FileHandle handle) { - throw new NotImplementedException(); + return FsManager.GetFileSize(out fileSize, handle); } public Result SetFileSize(FileHandle handle, long size) { - throw new NotImplementedException(); + return FsManager.SetFileSize(handle, size); } public OpenMode GetFileOpenMode(FileHandle handle) { - throw new NotImplementedException(); + return FsManager.GetFileOpenMode(handle); } public void CloseFile(FileHandle handle) { - throw new NotImplementedException(); + FsManager.CloseFile(handle); } } } diff --git a/src/LibHac/FsClient/FileSystemClient.FileSystem.cs b/src/LibHac/FsClient/FileSystemClient.FileSystem.cs index ebd4ed12..a0f6bd2e 100644 --- a/src/LibHac/FsClient/FileSystemClient.FileSystem.cs +++ b/src/LibHac/FsClient/FileSystemClient.FileSystem.cs @@ -1,4 +1,3 @@ -using System; using LibHac.Fs; namespace LibHac.FsClient @@ -7,77 +6,77 @@ namespace LibHac.FsClient { public Result CreateDirectory(string path) { - throw new NotImplementedException(); + return FsManager.CreateDirectory(path); } public Result CreateFile(string path, long size) { - throw new NotImplementedException(); + return CreateFile(path, size, CreateFileOptions.None); } public Result CreateFile(string path, long size, CreateFileOptions options) { - throw new NotImplementedException(); + return FsManager.CreateFile(path, size, options); } public Result DeleteDirectory(string path) { - throw new NotImplementedException(); + return FsManager.DeleteDirectory(path); } public Result DeleteDirectoryRecursively(string path) { - throw new NotImplementedException(); + return FsManager.DeleteDirectoryRecursively(path); } public Result CleanDirectoryRecursively(string path) { - throw new NotImplementedException(); + return FsManager.CleanDirectoryRecursively(path); } public Result DeleteFile(string path) { - throw new NotImplementedException(); + return FsManager.DeleteFile(path); } public Result RenameDirectory(string oldPath, string newPath) { - throw new NotImplementedException(); + return FsManager.RenameDirectory(oldPath, newPath); } public Result RenameFile(string oldPath, string newPath) { - throw new NotImplementedException(); + return FsManager.RenameFile(oldPath, newPath); } public Result GetEntryType(out DirectoryEntryType type, string path) { - throw new NotImplementedException(); + return FsManager.GetEntryType(out type, path); } public Result OpenFile(out FileHandle handle, string path, OpenMode mode) { - throw new NotImplementedException(); + return FsManager.OpenFile(out handle, path, mode); } public Result OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) { - throw new NotImplementedException(); + return FsManager.OpenDirectory(out handle, path, mode); } - public Result GetFreeSpaceSize(out long size, string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - throw new NotImplementedException(); + return FsManager.GetFreeSpaceSize(out freeSpace, path); } - public Result GetTotalSpaceSize(out long size, string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - throw new NotImplementedException(); + return FsManager.GetTotalSpaceSize(out totalSpace, path); } public Result Commit(string mountName) { - throw new NotImplementedException(); + return FsManager.Commit(mountName); } } } \ No newline at end of file diff --git a/src/LibHac/FsClient/FileSystemManager.cs b/src/LibHac/FsClient/FileSystemManager.cs index 87d442ce..eadb8415 100644 --- a/src/LibHac/FsClient/FileSystemManager.cs +++ b/src/LibHac/FsClient/FileSystemManager.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Runtime.CompilerServices; using LibHac.Fs; using LibHac.FsClient.Accessors; @@ -386,12 +385,27 @@ namespace LibHac.FsClient // ========================== // Operations on file handles // ========================== - public Result ReadFile(out long bytesRead, FileHandle handle, Span destination, long offset) + public Result ReadFile(FileHandle handle, long offset, Span destination) { - return ReadFile(out bytesRead, handle, destination, offset, ReadOption.None); + return ReadFile(handle, offset, destination, ReadOption.None); } - public Result ReadFile(out long bytesRead, FileHandle handle, Span destination, long offset, ReadOption option) + public Result ReadFile(FileHandle handle, long offset, Span destination, ReadOption option) + { + Result rc = ReadFile(out long bytesRead, handle, offset, destination, option); + if (rc.IsFailure()) return rc; + + if (bytesRead == destination.Length) return Result.Success; + + return ResultFs.ValueOutOfRange.Log(); + } + + public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination) + { + return ReadFile(out bytesRead, handle, offset, destination, ReadOption.None); + } + + public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination, ReadOption option) { Result rc; @@ -512,22 +526,7 @@ namespace LibHac.FsClient return handle.Directory.GetEntryCount(out count); } - public IEnumerable ReadDirectory(DirectoryHandle handle) - { - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - IEnumerable entries = handle.Directory.Read(); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); - return entries; - } - - return handle.Directory.Read(); - } - - public Result ReadDirectory2(out long entriesRead, Span entryBuffer, DirectoryHandle handle) + public Result ReadDirectory(out long entriesRead, Span entryBuffer, DirectoryHandle handle) { Result rc; diff --git a/src/LibHac/FsClient/FileSystemManagerUtils.cs b/src/LibHac/FsClient/FileSystemManagerUtils.cs index af9bf0a6..e1e23cdc 100644 --- a/src/LibHac/FsClient/FileSystemManagerUtils.cs +++ b/src/LibHac/FsClient/FileSystemManagerUtils.cs @@ -1,6 +1,7 @@ using System; using System.Buffers; using System.Collections.Generic; +using LibHac.Common; using LibHac.Fs; using LibHac.FsClient.Accessors; @@ -16,7 +17,7 @@ namespace LibHac.FsClient using (sourceHandle) { - foreach (DirectoryEntryEx entry in fs.ReadDirectory(sourceHandle)) + foreach (DirectoryEntryEx entry in fs.EnumerateEntries(sourcePath, "*", SearchOptions.Default)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); @@ -72,7 +73,7 @@ namespace LibHac.FsClient int toRead = (int)Math.Min(fileSize - offset, bufferSize); Span buf = buffer.AsSpan(0, toRead); - rc = fs.ReadFile(out long _, sourceHandle, buf, offset); + rc = fs.ReadFile(out long _, sourceHandle, offset, buf); if (rc.IsFailure()) return rc; rc = fs.WriteFile(destHandle, buf, offset); @@ -110,12 +111,18 @@ namespace LibHac.FsClient bool ignoreCase = searchOptions.HasFlag(SearchOptions.CaseInsensitive); bool recurse = searchOptions.HasFlag(SearchOptions.RecurseSubdirectories); + DirectoryEntry dirEntry = default; fs.OpenDirectory(out DirectoryHandle sourceHandle, path, OpenDirectoryMode.All).ThrowIfFailure(); using (sourceHandle) { - foreach (DirectoryEntryEx entry in fs.ReadDirectory(sourceHandle)) + while (true) { + fs.ReadDirectory(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry), sourceHandle); + if (entriesRead == 0) break; + + DirectoryEntryEx entry = FileSystemExtensions.GetDirectoryEntryEx(ref dirEntry, path); + if (PathTools.MatchesPattern(searchPattern, entry.Name, ignoreCase)) { yield return entry; @@ -123,9 +130,9 @@ namespace LibHac.FsClient if (entry.Type != DirectoryEntryType.Directory || !recurse) continue; - string subPath = PathTools.Normalize(PathTools.Combine(path, entry.Name)); - - IEnumerable subEntries = fs.EnumerateEntries(subPath, searchPattern, searchOptions); + IEnumerable subEntries = + fs.EnumerateEntries(PathTools.Combine(path, entry.Name), searchPattern, + searchOptions); foreach (DirectoryEntryEx subEntry in subEntries) { diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index 1614a723..9aa361ee 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -30,7 +30,7 @@ namespace hactoolnet using (sourceHandle) { - foreach (DirectoryEntryEx entry in fs.ReadDirectory(sourceHandle)) + foreach (DirectoryEntryEx entry in fs.EnumerateEntries(sourcePath, "*", SearchOptions.Default)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); @@ -92,7 +92,7 @@ namespace hactoolnet int toRead = (int)Math.Min(fileSize - offset, bufferSize); Span buf = buffer.AsSpan(0, toRead); - rc = fs.ReadFile(out long _, sourceHandle, buf, offset); + rc = fs.ReadFile(out long _, sourceHandle, offset, buf); if (rc.IsFailure()) return rc; rc = fs.WriteFile(destHandle, buf, offset); From 4bbfa057d2c5dee9ddd0e2db5afb8a5980b5d7e4 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 16 Sep 2019 16:42:32 -0500 Subject: [PATCH 16/46] Add U8String class and some FileSystemClient functions --- src/LibHac/Common/StringUtils.cs | 14 ++-- src/LibHac/Common/U8Span.cs | 42 +++++++++++ src/LibHac/Common/U8SpanMutable.cs | 46 ++++++++++++ src/LibHac/Common/U8String.cs | 41 +++++++++++ src/LibHac/Common/U8StringHelpers.cs | 15 ++++ src/LibHac/Common/U8StringMutable.cs | 48 +++++++++++++ src/LibHac/Fs/DirectoryUtils.cs | 4 +- src/LibHac/Fs/FileSystemExtensions.cs | 4 +- src/LibHac/Fs/FsEnums.cs | 6 ++ .../FsClient/Accessors/FileSystemAccessor.cs | 11 ++- src/LibHac/FsClient/ContentStorage.cs | 70 +++++++++++++++++++ src/LibHac/FsClient/FileSystemClient.Mount.cs | 22 ++++++ src/LibHac/FsClient/FileSystemClient.cs | 16 ++++- src/LibHac/FsClient/FileSystemManager.cs | 14 +++- src/LibHac/FsClient/FileSystemManagerUtils.cs | 4 +- .../FsClient/ICommonMountNameGenerator.cs | 9 +++ src/LibHac/FsClient/MountHelpers.cs | 33 +++++++++ src/LibHac/FsService/FileSystemProxy.cs | 7 ++ src/LibHac/FsService/FileSystemProxyCore.cs | 44 ++++++++++++ src/LibHac/FsService/IFileSystemProxy.cs | 1 + src/LibHac/FsService/Util.cs | 15 +++- src/hactoolnet/ProcessNca.cs | 13 ++-- src/hactoolnet/ProcessSave.cs | 7 +- 23 files changed, 455 insertions(+), 31 deletions(-) create mode 100644 src/LibHac/Common/U8Span.cs create mode 100644 src/LibHac/Common/U8SpanMutable.cs create mode 100644 src/LibHac/Common/U8String.cs create mode 100644 src/LibHac/Common/U8StringHelpers.cs create mode 100644 src/LibHac/Common/U8StringMutable.cs create mode 100644 src/LibHac/FsClient/ContentStorage.cs create mode 100644 src/LibHac/FsClient/FileSystemClient.Mount.cs create mode 100644 src/LibHac/FsClient/ICommonMountNameGenerator.cs create mode 100644 src/LibHac/FsClient/MountHelpers.cs diff --git a/src/LibHac/Common/StringUtils.cs b/src/LibHac/Common/StringUtils.cs index 364d8396..b4501ea7 100644 --- a/src/LibHac/Common/StringUtils.cs +++ b/src/LibHac/Common/StringUtils.cs @@ -65,21 +65,19 @@ namespace LibHac.Common return iDest; } - - public static string FromUtf8Z(this Span value) => FromUtf8Z((ReadOnlySpan)value); - public static string FromUtf8Z(this ReadOnlySpan value) + public static string Utf8ToString(ReadOnlySpan value) { - int i; - for (i = 0; i < value.Length && value[i] != 0; i++) { } - - value = value.Slice(0, i); - #if STRING_SPAN return Encoding.UTF8.GetString(value); #else return Encoding.UTF8.GetString(value.ToArray()); #endif } + + public static string Utf8ZToString(ReadOnlySpan value) + { + return Utf8ToString(value.Slice(0, GetLength(value))); + } } } diff --git a/src/LibHac/Common/U8Span.cs b/src/LibHac/Common/U8Span.cs new file mode 100644 index 00000000..c58aa3e7 --- /dev/null +++ b/src/LibHac/Common/U8Span.cs @@ -0,0 +1,42 @@ +using System; +using System.Diagnostics; +using System.Text; + +namespace LibHac.Common +{ + [DebuggerDisplay("{ToString()}")] + public ref struct U8Span + { + private readonly ReadOnlySpan _buffer; + + public ReadOnlySpan Value => _buffer; + public int Length => _buffer.Length; + + public byte this[int i] + { + get => _buffer[i]; + } + + public U8Span(ReadOnlySpan value) + { + _buffer = value; + } + + public U8Span(string value) + { + _buffer = Encoding.UTF8.GetBytes(value); + } + + public static implicit operator ReadOnlySpan(U8Span value) => value.Value; + + public static explicit operator string(U8Span value) => value.ToString(); + public static explicit operator U8Span(string value) => new U8Span(value); + + public override string ToString() + { + return StringUtils.Utf8ToString(_buffer); + } + + public bool IsNull() => _buffer == default; + } +} diff --git a/src/LibHac/Common/U8SpanMutable.cs b/src/LibHac/Common/U8SpanMutable.cs new file mode 100644 index 00000000..d0edcfa1 --- /dev/null +++ b/src/LibHac/Common/U8SpanMutable.cs @@ -0,0 +1,46 @@ +using System; +using System.Diagnostics; +using System.Text; + +namespace LibHac.Common +{ + [DebuggerDisplay("{ToString()}")] + public ref struct U8SpanMutable + { + private readonly Span _buffer; + + public Span Value => _buffer; + public int Length => _buffer.Length; + + public byte this[int i] + { + get => _buffer[i]; + set => _buffer[i] = value; + } + + public U8SpanMutable(Span value) + { + _buffer = value; + } + + public U8SpanMutable(string value) + { + _buffer = Encoding.UTF8.GetBytes(value); + } + + public static implicit operator U8Span(U8SpanMutable value) => new U8Span(value._buffer); + + public static implicit operator ReadOnlySpan(U8SpanMutable value) => value.Value; + public static implicit operator Span(U8SpanMutable value) => value.Value; + + public static explicit operator string(U8SpanMutable value) => value.ToString(); + public static explicit operator U8SpanMutable(string value) => new U8SpanMutable(value); + + public override string ToString() + { + return StringUtils.Utf8ZToString(_buffer); + } + + public bool IsNull() => _buffer == default; + } +} diff --git a/src/LibHac/Common/U8String.cs b/src/LibHac/Common/U8String.cs new file mode 100644 index 00000000..df952cf5 --- /dev/null +++ b/src/LibHac/Common/U8String.cs @@ -0,0 +1,41 @@ +using System; +using System.Diagnostics; +using System.Text; + +namespace LibHac.Common +{ + [DebuggerDisplay("{ToString()}")] + public struct U8String + { + private readonly byte[] _buffer; + + public ReadOnlySpan Value => _buffer; + public int Length => _buffer.Length; + + public byte this[int i] => _buffer[i]; + + public U8String(byte[] value) + { + _buffer = value; + } + + public U8String(string value) + { + _buffer = Encoding.UTF8.GetBytes(value); + } + + public static implicit operator U8Span(U8String value) => new U8Span(value._buffer); + + public static implicit operator ReadOnlySpan(U8String value) => value.Value; + + public static explicit operator string(U8String value) => value.ToString(); + public static explicit operator U8String(string value) => new U8String(value); + + public override string ToString() + { + return StringUtils.Utf8ToString(_buffer); + } + + public bool IsNull() => _buffer == null; + } +} diff --git a/src/LibHac/Common/U8StringHelpers.cs b/src/LibHac/Common/U8StringHelpers.cs new file mode 100644 index 00000000..003b61fb --- /dev/null +++ b/src/LibHac/Common/U8StringHelpers.cs @@ -0,0 +1,15 @@ +namespace LibHac.Common +{ + public static class U8StringHelpers + { + public static U8String AsU8String(this string value) + { + return new U8String(value); + } + + public static U8Span AsU8Span(this string value) + { + return new U8Span(value); + } + } +} diff --git a/src/LibHac/Common/U8StringMutable.cs b/src/LibHac/Common/U8StringMutable.cs new file mode 100644 index 00000000..2bb7c75b --- /dev/null +++ b/src/LibHac/Common/U8StringMutable.cs @@ -0,0 +1,48 @@ +using System; +using System.Diagnostics; +using System.Text; + +namespace LibHac.Common +{ + [DebuggerDisplay("{ToString()}")] + public struct U8StringMutable + { + private readonly byte[] _buffer; + + public Span Value => _buffer; + public int Length => _buffer.Length; + + public byte this[int i] + { + get => _buffer[i]; + set => _buffer[i] = value; + } + + public U8StringMutable(byte[] value) + { + _buffer = value; + } + + public U8StringMutable(string value) + { + _buffer = Encoding.UTF8.GetBytes(value); + } + + public static implicit operator U8String(U8StringMutable value) => new U8String(value._buffer); + public static implicit operator U8SpanMutable(U8StringMutable value) => new U8SpanMutable(value._buffer); + public static implicit operator U8Span(U8StringMutable value) => new U8Span(value._buffer); + + public static implicit operator ReadOnlySpan(U8StringMutable value) => value.Value; + public static implicit operator Span(U8StringMutable value) => value.Value; + + public static explicit operator string(U8StringMutable value) => value.ToString(); + public static explicit operator U8StringMutable(string value) => new U8StringMutable(value); + + public override string ToString() + { + return StringUtils.Utf8ZToString(_buffer); + } + + public bool IsNull() => _buffer == null; + } +} diff --git a/src/LibHac/Fs/DirectoryUtils.cs b/src/LibHac/Fs/DirectoryUtils.cs index 2ff0839f..1ea54ecc 100644 --- a/src/LibHac/Fs/DirectoryUtils.cs +++ b/src/LibHac/Fs/DirectoryUtils.cs @@ -39,7 +39,7 @@ namespace LibHac.Fs try { - Result rc = sourceFs.OpenFile(out srcFile, sourcePath.FromUtf8Z(), OpenMode.Read); + Result rc = sourceFs.OpenFile(out srcFile, StringUtils.Utf8ZToString(sourcePath), OpenMode.Read); if (rc.IsFailure()) return rc; FsPath dstPath = default; @@ -51,7 +51,7 @@ namespace LibHac.Fs throw new ArgumentException(); } - string dstPathStr = dstPath.Str.FromUtf8Z(); + string dstPathStr = StringUtils.Utf8ZToString(dstPath.Str); rc = destFs.CreateFile(dstPathStr, dirEntry.Size, CreateFileOptions.None); if (rc.IsFailure()) return rc; diff --git a/src/LibHac/Fs/FileSystemExtensions.cs b/src/LibHac/Fs/FileSystemExtensions.cs index 5fca64dd..35495263 100644 --- a/src/LibHac/Fs/FileSystemExtensions.cs +++ b/src/LibHac/Fs/FileSystemExtensions.cs @@ -82,7 +82,7 @@ namespace LibHac.Fs fileSystem.OpenDirectory(out IDirectory directory, path, OpenDirectoryMode.All).ThrowIfFailure(); - while(true) + while (true) { directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref dirEntry)).ThrowIfFailure(); if (entriesRead == 0) break; @@ -109,7 +109,7 @@ namespace LibHac.Fs internal static DirectoryEntryEx GetDirectoryEntryEx(ref DirectoryEntry entry, string parentPath) { - string name = entry.Name.FromUtf8Z(); + string name = StringUtils.Utf8ZToString(entry.Name); string path = PathTools.Combine(parentPath, name); var entryEx = new DirectoryEntryEx(name, path, entry.Type, entry.Size); diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs index edb8f0b2..210d231d 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -53,4 +53,10 @@ ProperSystem = 100, Safe = 101 } + + public enum CustomStorageId + { + User = 0, + SdCard = 1 + } } diff --git a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs index 8916322b..a52fe3c2 100644 --- a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs +++ b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs @@ -11,6 +11,7 @@ namespace LibHac.FsClient.Accessors private IFileSystem FileSystem { get; } internal FileSystemManager FsManager { get; } + private ICommonMountNameGenerator MountNameGenerator { get; } private HashSet OpenFiles { get; } = new HashSet(); private HashSet OpenDirectories { get; } = new HashSet(); @@ -19,11 +20,12 @@ namespace LibHac.FsClient.Accessors internal bool IsAccessLogEnabled { get; set; } - public FileSystemAccessor(string name, IFileSystem baseFileSystem, FileSystemManager fsManager) + public FileSystemAccessor(string name, IFileSystem baseFileSystem, FileSystemManager fsManager, ICommonMountNameGenerator nameGenerator) { Name = name; FileSystem = baseFileSystem; FsManager = fsManager; + MountNameGenerator = nameGenerator; } public Result CreateDirectory(string path) @@ -147,6 +149,13 @@ namespace LibHac.FsClient.Accessors return FileSystem.QueryEntry(outBuffer, inBuffer, queryId, path); } + public Result GetCommonMountName(Span nameBuffer) + { + if (MountNameGenerator == null) return ResultFs.PreconditionViolation; + + return MountNameGenerator.Generate(nameBuffer); + } + internal void NotifyCloseFile(FileAccessor file) { lock (_locker) diff --git a/src/LibHac/FsClient/ContentStorage.cs b/src/LibHac/FsClient/ContentStorage.cs new file mode 100644 index 00000000..a84137aa --- /dev/null +++ b/src/LibHac/FsClient/ContentStorage.cs @@ -0,0 +1,70 @@ +using System; +using LibHac.Common; +using LibHac.Fs; +using LibHac.FsService; + +namespace LibHac.FsClient +{ + public static class ContentStorage + { + private static readonly U8String ContentStorageMountNameSystem = new U8String("@SystemContent"); + private static readonly U8String ContentStorageMountNameUser = new U8String("@UserContent"); + private static readonly U8String ContentStorageMountNameSdCard = new U8String("@SdCardContent"); + + public static Result MountContentStorage(this FileSystemClient fs, ContentStorageId storageId) + { + return MountContentStorage(fs, GetContentStorageMountName(storageId), storageId); + } + + public static Result MountContentStorage(this FileSystemClient fs, U8Span mountName, ContentStorageId storageId) + { + Result rc = MountHelpers.CheckMountNameAcceptingReservedMountName(mountName); + if (rc.IsFailure()) return rc; + + FileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + rc = fsProxy.OpenContentStorageFileSystem(out IFileSystem contentFs, storageId); + if (rc.IsFailure()) return rc; + + var mountNameGenerator = new ContentStorageCommonMountNameGenerator(storageId); + + return fs.Register(mountName, contentFs, mountNameGenerator); + } + + public static U8String GetContentStorageMountName(ContentStorageId storageId) + { + switch (storageId) + { + case ContentStorageId.System: + return ContentStorageMountNameSystem; + case ContentStorageId.User: + return ContentStorageMountNameUser; + case ContentStorageId.SdCard: + return ContentStorageMountNameSdCard; + default: + throw new ArgumentOutOfRangeException(nameof(storageId), storageId, null); + } + } + + private class ContentStorageCommonMountNameGenerator : ICommonMountNameGenerator + { + private ContentStorageId StorageId { get; } + + public ContentStorageCommonMountNameGenerator(ContentStorageId storageId) + { + StorageId = storageId; + } + + public Result Generate(Span nameBuffer) + { + U8String mountName = GetContentStorageMountName(StorageId); + + int length = StringUtils.Copy(nameBuffer, mountName); + nameBuffer[length] = (byte)':'; + nameBuffer[length + 1] = 0; + + return Result.Success; + } + } + } +} diff --git a/src/LibHac/FsClient/FileSystemClient.Mount.cs b/src/LibHac/FsClient/FileSystemClient.Mount.cs new file mode 100644 index 00000000..e98044d6 --- /dev/null +++ b/src/LibHac/FsClient/FileSystemClient.Mount.cs @@ -0,0 +1,22 @@ +using LibHac.Common; +using LibHac.Fs; +using LibHac.FsService; + +namespace LibHac.FsClient +{ + public partial class FileSystemClient + { + public Result MountCustomStorage(U8Span mountName, CustomStorageId storageId) + { + Result rc = MountHelpers.CheckMountName(mountName); + if (rc.IsFailure()) return rc; + + FileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); + + rc = fsProxy.OpenCustomStorageFileSystem(out IFileSystem customFs, storageId); + if (rc.IsFailure()) return rc; + + return FsManager.Register(mountName, customFs); + } + } +} diff --git a/src/LibHac/FsClient/FileSystemClient.cs b/src/LibHac/FsClient/FileSystemClient.cs index e5cfb5b8..8bc0a42a 100644 --- a/src/LibHac/FsClient/FileSystemClient.cs +++ b/src/LibHac/FsClient/FileSystemClient.cs @@ -1,4 +1,6 @@ -using LibHac.FsService; +using LibHac.Common; +using LibHac.Fs; +using LibHac.FsService; namespace LibHac.FsClient { @@ -16,7 +18,7 @@ namespace LibHac.FsClient FsManager = new FileSystemManager(timer); } - private FileSystemProxy GetFileSystemProxyServiceObject() + public FileSystemProxy GetFileSystemProxyServiceObject() { if (FsProxy != null) return FsProxy; @@ -29,5 +31,15 @@ namespace LibHac.FsClient return FsProxy; } } + + public Result Register(U8Span mountName, IFileSystem fileSystem) + { + return FsManager.Register(mountName, fileSystem); + } + + public Result Register(U8Span mountName, IFileSystem fileSystem, ICommonMountNameGenerator nameGenerator) + { + return FsManager.Register(mountName, fileSystem, nameGenerator); + } } } diff --git a/src/LibHac/FsClient/FileSystemManager.cs b/src/LibHac/FsClient/FileSystemManager.cs index eadb8415..45e2c4fc 100644 --- a/src/LibHac/FsClient/FileSystemManager.cs +++ b/src/LibHac/FsClient/FileSystemManager.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.CompilerServices; +using LibHac.Common; using LibHac.Fs; using LibHac.FsClient.Accessors; @@ -32,13 +33,20 @@ namespace LibHac.FsClient Time = timer; } - public void Register(string mountName, IFileSystem fileSystem) + public Result Register(U8Span mountName, IFileSystem fileSystem) { - var accessor = new FileSystemAccessor(mountName, fileSystem, this); + return Register(mountName, fileSystem, null); + } - MountTable.Mount(accessor).ThrowIfFailure(); + public Result Register(U8Span mountName, IFileSystem fileSystem, ICommonMountNameGenerator nameGenerator) + { + var accessor = new FileSystemAccessor(mountName.ToString(), fileSystem, this, nameGenerator); + + Result rc = MountTable.Mount(accessor); + if (rc.IsFailure()) return rc; accessor.IsAccessLogEnabled = IsEnabledAccessLog(); + return Result.Success; } public void Unmount(string mountName) diff --git a/src/LibHac/FsClient/FileSystemManagerUtils.cs b/src/LibHac/FsClient/FileSystemManagerUtils.cs index e1e23cdc..eb2add2c 100644 --- a/src/LibHac/FsClient/FileSystemManagerUtils.cs +++ b/src/LibHac/FsClient/FileSystemManagerUtils.cs @@ -131,12 +131,10 @@ namespace LibHac.FsClient if (entry.Type != DirectoryEntryType.Directory || !recurse) continue; IEnumerable subEntries = - fs.EnumerateEntries(PathTools.Combine(path, entry.Name), searchPattern, - searchOptions); + fs.EnumerateEntries(PathTools.Combine(path, entry.Name), searchPattern, searchOptions); foreach (DirectoryEntryEx subEntry in subEntries) { - subEntry.FullPath = PathTools.Combine(path, subEntry.Name); yield return subEntry; } } diff --git a/src/LibHac/FsClient/ICommonMountNameGenerator.cs b/src/LibHac/FsClient/ICommonMountNameGenerator.cs new file mode 100644 index 00000000..937c58d2 --- /dev/null +++ b/src/LibHac/FsClient/ICommonMountNameGenerator.cs @@ -0,0 +1,9 @@ +using System; + +namespace LibHac.FsClient +{ + public interface ICommonMountNameGenerator + { + Result Generate(Span nameBuffer); + } +} \ No newline at end of file diff --git a/src/LibHac/FsClient/MountHelpers.cs b/src/LibHac/FsClient/MountHelpers.cs new file mode 100644 index 00000000..18799d41 --- /dev/null +++ b/src/LibHac/FsClient/MountHelpers.cs @@ -0,0 +1,33 @@ +using LibHac.Common; +using LibHac.Fs; + +namespace LibHac.FsClient +{ + internal static class MountHelpers + { + public static Result CheckMountName(U8Span name) + { + if (name.IsNull()) return ResultFs.NullArgument.Log(); + + if (name.Length > 0 && name[0] == '@') return ResultFs.InvalidMountName.Log(); + if (!CheckMountNameImpl(name)) return ResultFs.InvalidMountName.Log(); + + return Result.Success; + } + + public static Result CheckMountNameAcceptingReservedMountName(U8Span name) + { + if (name.IsNull()) return ResultFs.NullArgument.Log(); + + if (!CheckMountNameImpl(name)) return ResultFs.InvalidMountName.Log(); + + return Result.Success; + } + + private static bool CheckMountNameImpl(U8Span name) + { + // Todo + return true; + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index 80da9c15..4449c91a 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -95,6 +95,13 @@ namespace LibHac.FsService return FsProxyCore.OpenContentStorageFileSystem(out fileSystem, storageId); } + public Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + return FsProxyCore.OpenCustomStorageFileSystem(out fileSystem, storageId); + } + public Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute) { diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 8c3e0e16..58250891 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -75,6 +75,50 @@ namespace LibHac.FsService EncryptedFsKeyId.Content, SdEncryptionSeed); } + public Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId) + { + fileSystem = default; + + switch (storageId) + { + case CustomStorageId.SdCard: + { + Result rc = FsCreators.SdFileSystemCreator.Create(out IFileSystem sdFs); + if (rc.IsFailure()) return rc; + + string customStorageDir = Util.GetCustomStorageDirectoryName(CustomStorageId.SdCard); + string subDirName = $"/{NintendoDirectoryName}/{customStorageDir}"; + + rc = Util.CreateSubFileSystem(out IFileSystem subFs, sdFs, subDirName, true); + if (rc.IsFailure()) return rc; + + rc = FsCreators.EncryptedFileSystemCreator.Create(out IFileSystem encryptedFs, subFs, + EncryptedFsKeyId.CustomStorage, SdEncryptionSeed); + if (rc.IsFailure()) return rc; + + fileSystem = encryptedFs; + return Result.Success; + } + case CustomStorageId.User: + { + Result rc = FsCreators.BuiltInStorageFileSystemCreator.Create(out IFileSystem userFs, string.Empty, + BisPartitionId.User); + if (rc.IsFailure()) return rc; + + string customStorageDir = Util.GetCustomStorageDirectoryName(CustomStorageId.User); + string subDirName = $"/{customStorageDir}"; + + rc = Util.CreateSubFileSystem(out IFileSystem subFs, userFs, subDirName, true); + if (rc.IsFailure()) return rc; + + fileSystem = subFs; + return Result.Success; + } + default: + return ResultFs.InvalidArgument.Log(); + } + } + public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) { seed.CopyTo(SdEncryptionSeed); diff --git a/src/LibHac/FsService/IFileSystemProxy.cs b/src/LibHac/FsService/IFileSystemProxy.cs index cd3ac661..59d665f3 100644 --- a/src/LibHac/FsService/IFileSystemProxy.cs +++ b/src/LibHac/FsService/IFileSystemProxy.cs @@ -12,6 +12,7 @@ namespace LibHac.FsService Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute); Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute); Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId); + Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId); Result SetSdCardEncryptionSeed(ReadOnlySpan seed); Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); Result SetSaveDataRootPath(string path); diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs index 8ac791bd..b6ed2b2a 100644 --- a/src/LibHac/FsService/Util.cs +++ b/src/LibHac/FsService/Util.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using System; +using LibHac.Fs; namespace LibHac.FsService { @@ -48,5 +49,17 @@ namespace LibHac.FsService spaceId == SaveDataSpaceId.ProperSystem || spaceId == SaveDataSpaceId.Safe; } + + public static string GetCustomStorageDirectoryName(CustomStorageId storageId) + { + switch (storageId) + { + case CustomStorageId.User: + case CustomStorageId.SdCard: + return "CustomStorage0"; + default: + throw new ArgumentOutOfRangeException(nameof(storageId), storageId, null); + } + } } } diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index 73b94ce9..5cfc9e65 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -1,6 +1,7 @@ using System.IO; using System.Text; using LibHac; +using LibHac.Common; using LibHac.Fs; using LibHac.Fs.NcaUtils; using LibHac.FsClient; @@ -47,8 +48,8 @@ namespace hactoolnet string mountName = $"section{i}"; - fs.Register(mountName, OpenFileSystem(i)); - fs.Register("output", new LocalFileSystem(ctx.Options.SectionOutDir[i])); + fs.Register(mountName.AsU8Span(), OpenFileSystem(i)); + fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.SectionOutDir[i])); FsUtils.CopyDirectoryWithProgress(fs, mountName + ":/", "output:/", logger: ctx.Logger); @@ -96,8 +97,8 @@ namespace hactoolnet { FileSystemManager fs = ctx.Horizon.Fs; - fs.Register("rom", OpenFileSystemByType(NcaSectionType.Data)); - fs.Register("output", new LocalFileSystem(ctx.Options.RomfsOutDir)); + fs.Register("rom".AsU8Span(), OpenFileSystemByType(NcaSectionType.Data)); + fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir)); FsUtils.CopyDirectoryWithProgress(fs, "rom:/", "output:/", logger: ctx.Logger); @@ -153,8 +154,8 @@ namespace hactoolnet { FileSystemManager fs = ctx.Horizon.Fs; - fs.Register("code", OpenFileSystemByType(NcaSectionType.Code)); - fs.Register("output", new LocalFileSystem(ctx.Options.ExefsOutDir)); + fs.Register("code".AsU8Span(), OpenFileSystemByType(NcaSectionType.Code)); + fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir)); FsUtils.CopyDirectoryWithProgress(fs, "code:/", "output:/", logger: ctx.Logger); diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index ae1b7d6b..3bc937c3 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Text; using LibHac; +using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Save; using LibHac.FsClient; @@ -30,7 +31,7 @@ namespace hactoolnet var save = new SaveDataFileSystem(ctx.Keyset, file, ctx.Options.IntegrityLevel, true); FileSystemManager fs = ctx.Horizon.Fs; - fs.Register("save", save); + fs.Register("save".AsU8Span(), save); if (ctx.Options.Validate) { @@ -39,7 +40,7 @@ namespace hactoolnet if (ctx.Options.OutDir != null) { - fs.Register("output", new LocalFileSystem(ctx.Options.OutDir)); + fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.OutDir)); FsUtils.CopyDirectoryWithProgress(fs, "save:/", "output:/", logger: ctx.Logger); @@ -85,7 +86,7 @@ namespace hactoolnet if (ctx.Options.RepackSource != null) { - fs.Register("input", new LocalFileSystem(ctx.Options.RepackSource)); + fs.Register("input".AsU8Span(), new LocalFileSystem(ctx.Options.RepackSource)); fs.CleanDirectoryRecursively("save:/"); fs.Commit("save"); From 7222c7d4693a3c1ac94294d1fb3b0d20f6cffe1e Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 16 Sep 2019 22:05:22 -0500 Subject: [PATCH 17/46] Add a few more method definitions to IFileSystemProxy --- src/LibHac/Fs/FsEnums.cs | 20 ++++++++++++++++++++ src/LibHac/Fs/Save/Header.cs | 14 +++++++------- src/LibHac/Fs/SaveDataAttribute2.cs | 16 ++++++++++++++++ src/LibHac/Fs/SaveDataCreateInfo.cs | 10 ++++++++++ src/LibHac/Fs/SaveMetaCreateInfo.cs | 11 +++++++++++ src/LibHac/FsService/IFileSystemProxy.cs | 19 +++++++++++++++++-- src/LibHac/Ncm/TitleId.cs | 9 +++++++++ 7 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 src/LibHac/Fs/SaveDataAttribute2.cs create mode 100644 src/LibHac/Fs/SaveDataCreateInfo.cs create mode 100644 src/LibHac/Fs/SaveMetaCreateInfo.cs create mode 100644 src/LibHac/Ncm/TitleId.cs diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs index 210d231d..cb187dc8 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -59,4 +59,24 @@ User = 0, SdCard = 1 } + + public enum FileSystemType + { + Code = 0, + Data = 1, + Logo = 2, + ContentControl = 3, + ContentManual = 4, + ContentMeta = 5, + ContentData = 6, + ApplicationPackage = 7, + RegisteredUpdate = 8 + } + + public enum SaveMetaType : byte + { + None = 0, + Thumbnail = 1, + ExtensionInfo = 2 + } } diff --git a/src/LibHac/Fs/Save/Header.cs b/src/LibHac/Fs/Save/Header.cs index d6d06a67..a0bc4ef8 100644 --- a/src/LibHac/Fs/Save/Header.cs +++ b/src/LibHac/Fs/Save/Header.cs @@ -280,13 +280,13 @@ namespace LibHac.Fs.Save } } - public enum SaveDataType + public enum SaveDataType : byte { - SystemSaveData, - SaveData, - BcatDeliveryCacheStorage, - DeviceSaveData, - TemporaryStorage, - CacheStorage + SystemSaveData = 0, + SaveData = 1, + BcatDeliveryCacheStorage = 2, + DeviceSaveData = 3, + TemporaryStorage = 4, + CacheStorage = 5 } } diff --git a/src/LibHac/Fs/SaveDataAttribute2.cs b/src/LibHac/Fs/SaveDataAttribute2.cs new file mode 100644 index 00000000..0dd628a7 --- /dev/null +++ b/src/LibHac/Fs/SaveDataAttribute2.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; +using LibHac.Fs.Save; + +namespace LibHac.Fs +{ + [StructLayout(LayoutKind.Explicit, Size = 0x40)] + public struct SaveDataAttribute2 + { + [FieldOffset(0x00)] public ulong TitleId; + [FieldOffset(0x08)] public UserId UserId; + [FieldOffset(0x18)] public ulong SaveDataId; + [FieldOffset(0x20)] public SaveDataType Type; + [FieldOffset(0x21)] public byte Rank; + [FieldOffset(0x22)] public short Index; + } +} diff --git a/src/LibHac/Fs/SaveDataCreateInfo.cs b/src/LibHac/Fs/SaveDataCreateInfo.cs new file mode 100644 index 00000000..9dee82af --- /dev/null +++ b/src/LibHac/Fs/SaveDataCreateInfo.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace LibHac.Fs +{ + [StructLayout(LayoutKind.Explicit, Size = 0x40)] + public struct SaveDataCreateInfo + { + // Todo + } +} diff --git a/src/LibHac/Fs/SaveMetaCreateInfo.cs b/src/LibHac/Fs/SaveMetaCreateInfo.cs new file mode 100644 index 00000000..c22202db --- /dev/null +++ b/src/LibHac/Fs/SaveMetaCreateInfo.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace LibHac.Fs +{ + [StructLayout(LayoutKind.Explicit, Size = 0x10)] + public struct SaveMetaCreateInfo + { + [FieldOffset(0)] public int Size; + [FieldOffset(4)] public SaveMetaType Type; + } +} diff --git a/src/LibHac/FsService/IFileSystemProxy.cs b/src/LibHac/FsService/IFileSystemProxy.cs index 59d665f3..61b7a1b7 100644 --- a/src/LibHac/FsService/IFileSystemProxy.cs +++ b/src/LibHac/FsService/IFileSystemProxy.cs @@ -1,13 +1,28 @@ using System; +using LibHac.Common; using LibHac.Fs; +using LibHac.Ncm; namespace LibHac.FsService { public interface IFileSystemProxy { Result SetCurrentProcess(long processId); - Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId); + Result OpenDataFileSystemByCurrentProcess(out IFileSystem fileSystem); + Result OpenFileSystemWithPatch(out IFileSystem fileSystem, TitleId titleId, FileSystemType type); + Result OpenFileSystemWithId(out IFileSystem fileSystem, U8Span path, TitleId titleId, FileSystemType type); + Result OpenDataFileSystemByProgramId(out IFileSystem fileSystem, TitleId titleId); + Result OpenBisFileSystem(out IFileSystem fileSystem, U8Span rootPath, BisPartitionId partitionId); + Result OpenBisStorage(out IStorage storage, BisPartitionId partitionId); + Result InvalidateBisCache(); + Result OpenHostFileSystem(out IFileSystem fileSystem, U8Span subPath); Result OpenSdCardFileSystem(out IFileSystem fileSystem); + Result FormatSdCardFileSystem(); + Result DeleteSaveDataFileSystem(long saveDataId); + Result CreateSaveDataFileSystem(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo, ref SaveMetaCreateInfo metaCreateInfo); + Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo); + Result RegisterSaveDataFileSystemAtomicDeletion(ReadOnlySpan saveDataIds); + Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId); Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute); Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute); @@ -15,7 +30,7 @@ namespace LibHac.FsService Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId); Result SetSdCardEncryptionSeed(ReadOnlySpan seed); Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); - Result SetSaveDataRootPath(string path); + Result SetSaveDataRootPath(U8Span path); Result DisableAutoSaveDataCreation(); } } \ No newline at end of file diff --git a/src/LibHac/Ncm/TitleId.cs b/src/LibHac/Ncm/TitleId.cs new file mode 100644 index 00000000..9502bf10 --- /dev/null +++ b/src/LibHac/Ncm/TitleId.cs @@ -0,0 +1,9 @@ +namespace LibHac.Ncm +{ + public struct TitleId + { + public ulong Value; + + public static explicit operator ulong(TitleId titleId) => titleId.Value; + } +} From 7e2dd220792523fb40a603219c751bf2888f04c2 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Wed, 18 Sep 2019 16:29:27 -0500 Subject: [PATCH 18/46] Add more methods to IFileSystemProxy --- src/LibHac/Fs/FsEnums.cs | 5 +- src/LibHac/Fs/SaveDataAttribute2.cs | 16 ----- src/LibHac/Fs/SaveDataStructs.cs | 70 +++++++++++++++++++++ src/LibHac/FsService/IFileSystemProxy.cs | 37 +++++++++-- src/LibHac/FsService/ISaveDataInfoReader.cs | 9 +++ 5 files changed, 115 insertions(+), 22 deletions(-) delete mode 100644 src/LibHac/Fs/SaveDataAttribute2.cs create mode 100644 src/LibHac/Fs/SaveDataStructs.cs create mode 100644 src/LibHac/FsService/ISaveDataInfoReader.cs diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs index cb187dc8..f3613492 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -43,7 +43,7 @@ Writable = 2 } - public enum SaveDataSpaceId + public enum SaveDataSpaceId : byte { System = 0, User = 1, @@ -51,7 +51,8 @@ TemporaryStorage = 3, SdCache = 4, ProperSystem = 100, - Safe = 101 + Safe = 101, + BisAuto = 127 } public enum CustomStorageId diff --git a/src/LibHac/Fs/SaveDataAttribute2.cs b/src/LibHac/Fs/SaveDataAttribute2.cs deleted file mode 100644 index 0dd628a7..00000000 --- a/src/LibHac/Fs/SaveDataAttribute2.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Runtime.InteropServices; -using LibHac.Fs.Save; - -namespace LibHac.Fs -{ - [StructLayout(LayoutKind.Explicit, Size = 0x40)] - public struct SaveDataAttribute2 - { - [FieldOffset(0x00)] public ulong TitleId; - [FieldOffset(0x08)] public UserId UserId; - [FieldOffset(0x18)] public ulong SaveDataId; - [FieldOffset(0x20)] public SaveDataType Type; - [FieldOffset(0x21)] public byte Rank; - [FieldOffset(0x22)] public short Index; - } -} diff --git a/src/LibHac/Fs/SaveDataStructs.cs b/src/LibHac/Fs/SaveDataStructs.cs new file mode 100644 index 00000000..b4435b97 --- /dev/null +++ b/src/LibHac/Fs/SaveDataStructs.cs @@ -0,0 +1,70 @@ +using System; +using System.Runtime.InteropServices; +using LibHac.Common; +using LibHac.Fs.Save; +using LibHac.Ncm; + +namespace LibHac.Fs +{ + [StructLayout(LayoutKind.Explicit, Size = 0x40)] + public struct SaveDataAttribute2 + { + [FieldOffset(0x00)] public ulong TitleId; + [FieldOffset(0x08)] public UserId UserId; + [FieldOffset(0x18)] public ulong SaveDataId; + [FieldOffset(0x20)] public SaveDataType Type; + [FieldOffset(0x21)] public byte Rank; + [FieldOffset(0x22)] public short Index; + } + + [StructLayout(LayoutKind.Explicit, Size = 0x48)] + public struct SaveDataFilter + { + [FieldOffset(0x00)] public bool FilterByTitleId; + [FieldOffset(0x01)] public bool FilterBySaveDataType; + [FieldOffset(0x02)] public bool FilterByUserId; + [FieldOffset(0x03)] public bool FilterBySaveDataId; + [FieldOffset(0x04)] public bool FilterByIndex; + [FieldOffset(0x05)] public byte Rank; + + [FieldOffset(0x08)] public TitleId TitleID; + [FieldOffset(0x10)] public UserId UserId; + [FieldOffset(0x20)] public ulong SaveDataId; + [FieldOffset(0x28)] public SaveDataType SaveDataType; + [FieldOffset(0x2A)] public short Index; + } + + [StructLayout(LayoutKind.Explicit, Size = 0x50)] + public struct SaveDataFilterInternal + { + [FieldOffset(0x00)] public bool FilterBySaveDataSpaceId; + [FieldOffset(0x01)] public SaveDataSpaceId SpaceId; + + [FieldOffset(0x08)] public bool FilterByTitleId; + [FieldOffset(0x10)] public TitleId TitleID; + + [FieldOffset(0x18)] public bool FilterBySaveDataType; + [FieldOffset(0x19)] public SaveDataType SaveDataType; + + [FieldOffset(0x20)] public bool FilterByUserId; + [FieldOffset(0x28)] public UserId UserId; + + [FieldOffset(0x38)] public bool FilterBySaveDataId; + [FieldOffset(0x40)] public ulong SaveDataId; + + [FieldOffset(0x48)] public bool FilterByIndex; + [FieldOffset(0x4A)] public short Index; + + [FieldOffset(0x4C)] public int Rank; + } + + [StructLayout(LayoutKind.Explicit, Size = HashLength)] + public struct HashSalt + { + private const int HashLength = 0x20; + + [FieldOffset(0x00)] private byte _hashStart; + + public Span Hash => SpanHelpers.CreateSpan(ref _hashStart, HashLength); + } +} diff --git a/src/LibHac/FsService/IFileSystemProxy.cs b/src/LibHac/FsService/IFileSystemProxy.cs index 61b7a1b7..0498556d 100644 --- a/src/LibHac/FsService/IFileSystemProxy.cs +++ b/src/LibHac/FsService/IFileSystemProxy.cs @@ -18,19 +18,48 @@ namespace LibHac.FsService Result OpenHostFileSystem(out IFileSystem fileSystem, U8Span subPath); Result OpenSdCardFileSystem(out IFileSystem fileSystem); Result FormatSdCardFileSystem(); - Result DeleteSaveDataFileSystem(long saveDataId); + Result DeleteSaveDataFileSystem(ulong saveDataId); Result CreateSaveDataFileSystem(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo, ref SaveMetaCreateInfo metaCreateInfo); Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute2 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 OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId); - Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute); - Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, SaveDataAttribute attribute); + 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 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); + Result ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(Span extraDataBuffer, SaveDataSpaceId spaceId, ulong saveDataId); + Result ReadSaveDataFileSystemExtraData(Span extraDataBuffer, ulong saveDataId); + Result WriteSaveDataFileSystemExtraData(ulong saveDataId, SaveDataSpaceId spaceId, ReadOnlySpan extraDataBuffer); + Result OpenSaveDataInfoReader(out ISaveDataInfoReader infoReader); + Result OpenSaveDataInfoReaderBySaveDataSpaceId(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId); + Result OpenSaveDataInfoReaderOnlyCacheStorage(out ISaveDataInfoReader infoReader); + Result OpenSaveDataInternalStorageFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ulong saveDataId); + Result UpdateSaveDataMacForDebug(SaveDataSpaceId spaceId, ulong saveDataId); + 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 OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId); Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId); Result SetSdCardEncryptionSeed(ReadOnlySpan seed); Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); Result SetSaveDataRootPath(U8Span path); Result DisableAutoSaveDataCreation(); + Result SetGlobalAccessLogMode(int mode); + Result GetGlobalAccessLogMode(out int mode); + Result OutputAccessLogToSdCard(U8Span logString); + Result RegisterUpdatePartition(); + Result OpenRegisteredUpdatePartition(out IFileSystem fileSystem); } } \ No newline at end of file diff --git a/src/LibHac/FsService/ISaveDataInfoReader.cs b/src/LibHac/FsService/ISaveDataInfoReader.cs new file mode 100644 index 00000000..d0ece142 --- /dev/null +++ b/src/LibHac/FsService/ISaveDataInfoReader.cs @@ -0,0 +1,9 @@ +using System; + +namespace LibHac.FsService +{ + public interface ISaveDataInfoReader + { + Result ReadSaveDataInfo(out long readCount, Span saveDataInfoBuffer); + } +} \ No newline at end of file From 5ca698eda1dcc3d634ae33a0fba708c922b1a44d Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Wed, 18 Sep 2019 18:07:08 -0500 Subject: [PATCH 19/46] More IFileSystemProxy functions --- src/LibHac/Common/Id128.cs | 2 +- src/LibHac/FsService/IFileSystemProxy.cs | 4 ++++ src/LibHac/Ncm/StorageId.cs | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/LibHac/Ncm/StorageId.cs diff --git a/src/LibHac/Common/Id128.cs b/src/LibHac/Common/Id128.cs index eab8ab95..68deec6c 100644 --- a/src/LibHac/Common/Id128.cs +++ b/src/LibHac/Common/Id128.cs @@ -12,7 +12,7 @@ namespace LibHac.Common public readonly ulong High; public readonly ulong Low; - public static Id128 InvalidId = new Id128(0, 0); + public static readonly Id128 InvalidId = new Id128(0, 0); public Id128(ulong high, ulong low) { diff --git a/src/LibHac/FsService/IFileSystemProxy.cs b/src/LibHac/FsService/IFileSystemProxy.cs index 0498556d..146219ba 100644 --- a/src/LibHac/FsService/IFileSystemProxy.cs +++ b/src/LibHac/FsService/IFileSystemProxy.cs @@ -52,6 +52,10 @@ namespace LibHac.FsService Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId); Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId); + Result OpenDataStorageByCurrentProcess(out IStorage storage); + Result OpenDataStorageByProgramId(out IStorage storage, TitleId programId); + Result OpenDataStorageByDataId(out IStorage storage, TitleId dataId, StorageId storageId); + Result SetSdCardEncryptionSeed(ReadOnlySpan seed); Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); Result SetSaveDataRootPath(U8Span path); diff --git a/src/LibHac/Ncm/StorageId.cs b/src/LibHac/Ncm/StorageId.cs new file mode 100644 index 00000000..a19d8493 --- /dev/null +++ b/src/LibHac/Ncm/StorageId.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LibHac.Ncm +{ + public enum StorageId : byte + { + None = 0, + Host = 1, + GameCard = 2, + BuiltInSystem = 3, + BuiltInUser = 4, + SdCard = 5 + } +} From 115d7989053299f16870f6a80330c862e95319af Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 20 Sep 2019 00:40:14 -0500 Subject: [PATCH 20/46] Add more methods to IFileSystemProxy --- src/LibHac/Fs/FsEnums.cs | 12 +++++++ src/LibHac/Fs/FsPath.cs | 4 +++ src/LibHac/FsService/IDeviceOperator.cs | 7 ++++ src/LibHac/FsService/IFileSystemProxy.cs | 41 +++++++++++++++++++++--- src/LibHac/Ncm/StorageId.cs | 6 +--- src/LibHac/Spl/AccessKey.cs | 20 ++++++++++++ 6 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 src/LibHac/FsService/IDeviceOperator.cs create mode 100644 src/LibHac/Spl/AccessKey.cs diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs index f3613492..223f36fb 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -80,4 +80,16 @@ Thumbnail = 1, ExtensionInfo = 2 } + + public enum ImageDirectoryId + { + Nand = 0, + SdCard = 1 + } + + public enum CloudBackupWorkStorageId + { + Nand = 0, + SdCard = 1 + } } diff --git a/src/LibHac/Fs/FsPath.cs b/src/LibHac/Fs/FsPath.cs index 7db2b8f0..4f10eb67 100644 --- a/src/LibHac/Fs/FsPath.cs +++ b/src/LibHac/Fs/FsPath.cs @@ -1,9 +1,11 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; using LibHac.Common; namespace LibHac.Fs { + [DebuggerDisplay("{ToString()}")] [StructLayout(LayoutKind.Explicit, Size = MaxLength + 1)] public struct FsPath { @@ -12,5 +14,7 @@ namespace LibHac.Fs [FieldOffset(0)] private byte _str; public Span Str => SpanHelpers.CreateSpan(ref _str, MaxLength + 1); + + public override string ToString() => StringUtils.Utf8ZToString(Str); } } diff --git a/src/LibHac/FsService/IDeviceOperator.cs b/src/LibHac/FsService/IDeviceOperator.cs new file mode 100644 index 00000000..943b71fe --- /dev/null +++ b/src/LibHac/FsService/IDeviceOperator.cs @@ -0,0 +1,7 @@ +namespace LibHac.FsService +{ + public interface IDeviceOperator + { + + } +} \ No newline at end of file diff --git a/src/LibHac/FsService/IFileSystemProxy.cs b/src/LibHac/FsService/IFileSystemProxy.cs index 146219ba..ffc4d3fb 100644 --- a/src/LibHac/FsService/IFileSystemProxy.cs +++ b/src/LibHac/FsService/IFileSystemProxy.cs @@ -2,6 +2,7 @@ using LibHac.Common; using LibHac.Fs; using LibHac.Ncm; +using LibHac.Spl; namespace LibHac.FsService { @@ -10,12 +11,12 @@ namespace LibHac.FsService Result SetCurrentProcess(long processId); Result OpenDataFileSystemByCurrentProcess(out IFileSystem fileSystem); Result OpenFileSystemWithPatch(out IFileSystem fileSystem, TitleId titleId, FileSystemType type); - Result OpenFileSystemWithId(out IFileSystem fileSystem, U8Span path, TitleId titleId, FileSystemType type); + Result OpenFileSystemWithId(out IFileSystem fileSystem, ref FsPath path, TitleId titleId, FileSystemType type); Result OpenDataFileSystemByProgramId(out IFileSystem fileSystem, TitleId titleId); - Result OpenBisFileSystem(out IFileSystem fileSystem, U8Span rootPath, BisPartitionId partitionId); + Result OpenBisFileSystem(out IFileSystem fileSystem, ref FsPath rootPath, BisPartitionId partitionId); Result OpenBisStorage(out IStorage storage, BisPartitionId partitionId); Result InvalidateBisCache(); - Result OpenHostFileSystem(out IFileSystem fileSystem, U8Span subPath); + Result OpenHostFileSystem(out IFileSystem fileSystem, ref FsPath subPath); Result OpenSdCardFileSystem(out IFileSystem fileSystem); Result FormatSdCardFileSystem(); Result DeleteSaveDataFileSystem(ulong saveDataId); @@ -50,20 +51,52 @@ namespace LibHac.FsService Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute(ref SaveDataAttribute2 attribute, SaveDataSpaceId spaceId, ReadOnlySpan extraDataBuffer, ReadOnlySpan maskBuffer); Result OpenSaveDataMetaFile(out IFile file, SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute, SaveMetaType type); + Result ListAccessibleSaveDataOwnerId(out int readCount, Span idBuffer, TitleId programId, int startIndex, int bufferIdCount); + Result OpenImageDirectoryFileSystem(out IFileSystem fileSystem, ImageDirectoryId dirId); Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId); + Result OpenCloudBackupWorkStorageFileSystem(out IFileSystem fileSystem, CloudBackupWorkStorageId storageId); Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId); Result OpenDataStorageByCurrentProcess(out IStorage storage); Result OpenDataStorageByProgramId(out IStorage storage, TitleId programId); Result OpenDataStorageByDataId(out IStorage storage, TitleId dataId, StorageId storageId); + Result OpenPatchDataStorageByCurrentProcess(out IStorage storage); + Result OpenDataFileSystemWithProgramIndex(out IFileSystem fileSystem, byte programIndex); + Result OpenDataStorageWithProgramIndex(out IStorage storage, byte programIndex); + Result OpenDeviceOperator(out IDeviceOperator deviceOperator); + Result QuerySaveDataTotalSize(out long totalSize, long dataSize, long journalSize); + Result VerifySaveDataFileSystem(ulong saveDataId, Span readBuffer); + Result CorruptSaveDataFileSystem(ulong saveDataId); + Result CreatePaddingFile(long size); + Result DeleteAllPaddingFiles(); + Result GetRightsId(out RightsId rightsId, TitleId programId, StorageId storageId); + Result RegisterExternalKey(ref RightsId rightsId, ref AccessKey externalKey); + Result UnregisterAllExternalKey(); + Result GetRightsIdByPath(out RightsId rightsId, ref FsPath path); + Result GetRightsIdAndKeyGenerationByPath(out RightsId rightsId, out byte keyGeneration, ref FsPath path); + Result SetCurrentPosixTimeWithTimeDifference(long time, int difference); + Result GetFreeSpaceSizeForSaveData(out long freeSpaceSize, SaveDataSpaceId spaceId); + Result VerifySaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId, Span readBuffer); + Result CorruptSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId); + Result QuerySaveDataInternalStorageTotalSize(out long size, SaveDataSpaceId spaceId, ulong saveDataId); + Result GetSaveDataCommitId(out long commitId, SaveDataSpaceId spaceId, ulong saveDataId); + Result UnregisterExternalKey(ref RightsId rightsId); Result SetSdCardEncryptionSeed(ReadOnlySpan seed); + Result SetSdCardAccessibility(bool isAccessible); + Result IsSdCardAccessible(out bool isAccessible); + + Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path); Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); - Result SetSaveDataRootPath(U8Span path); + Result SetSaveDataRootPath(ref FsPath path); Result DisableAutoSaveDataCreation(); Result SetGlobalAccessLogMode(int mode); Result GetGlobalAccessLogMode(out int mode); Result OutputAccessLogToSdCard(U8Span logString); Result RegisterUpdatePartition(); Result OpenRegisteredUpdatePartition(out IFileSystem fileSystem); + + Result GetProgramIndexForAccessLog(out int programIndex, out int programCount); + Result OverrideSaveDataTransferTokenSignVerificationKey(ReadOnlySpan key); + Result CorruptSaveDataFileSystemByOffset(SaveDataSpaceId spaceId, ulong saveDataId, long offset); } } \ No newline at end of file diff --git a/src/LibHac/Ncm/StorageId.cs b/src/LibHac/Ncm/StorageId.cs index a19d8493..1fd4339a 100644 --- a/src/LibHac/Ncm/StorageId.cs +++ b/src/LibHac/Ncm/StorageId.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace LibHac.Ncm +namespace LibHac.Ncm { public enum StorageId : byte { diff --git a/src/LibHac/Spl/AccessKey.cs b/src/LibHac/Spl/AccessKey.cs new file mode 100644 index 00000000..987a55b8 --- /dev/null +++ b/src/LibHac/Spl/AccessKey.cs @@ -0,0 +1,20 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using LibHac.Common; + +namespace LibHac.Spl +{ + [DebuggerDisplay("{ToString()}")] + [StructLayout(LayoutKind.Sequential, Size = 0x10)] + public struct AccessKey + { + private long _dummy1; + private long _dummy2; + + public Span Key => SpanHelpers.CreateSpan(ref Unsafe.As(ref _dummy1), 0x10); + + public override string ToString() => Key.ToHexString(); + } +} From a7befc5612460e1e91a224d9ee1993c8ae935e74 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 20 Sep 2019 22:51:42 -0500 Subject: [PATCH 21/46] Add AccessPermissions enum --- src/LibHac/FsService/IDeviceOperator.cs | 4 +- src/LibHac/FsService/Permissions.cs | 169 ++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 src/LibHac/FsService/Permissions.cs diff --git a/src/LibHac/FsService/IDeviceOperator.cs b/src/LibHac/FsService/IDeviceOperator.cs index 943b71fe..bbb5b218 100644 --- a/src/LibHac/FsService/IDeviceOperator.cs +++ b/src/LibHac/FsService/IDeviceOperator.cs @@ -2,6 +2,8 @@ { public interface IDeviceOperator { - + Result IsSdCardInserted(out bool isInserted); + Result IsGameCardInserted(out bool isInserted); + Result GetGameCardHandle(out GameCardHandle handle); } } \ No newline at end of file diff --git a/src/LibHac/FsService/Permissions.cs b/src/LibHac/FsService/Permissions.cs new file mode 100644 index 00000000..aa773235 --- /dev/null +++ b/src/LibHac/FsService/Permissions.cs @@ -0,0 +1,169 @@ +using System; + +namespace LibHac.FsService +{ + /// + /// Permissions that control which storages or filesystems can be mounted or opened. + /// + public enum AccessPermissions + { + MountLogo = 0x0, + MountContentMeta = 0x1, + MountContentControl = 0x2, + MountContentManual = 0x3, + MountContentData = 0x4, + MountApplicationPackage = 0x5, + MountSaveDataStorage = 0x6, + MountContentStorage = 0x7, + MountImageAndVideoStorage = 0x8, + MountCloudBackupWorkStorage = 0x9, + MountCustomStorage = 0xA, + MountBisCalibrationFile = 0xB, + MountBisSafeMode = 0xC, + MountBisUser = 0xD, + MountBisSystem = 0xE, + MountBisSystemProperEncryption = 0xF, + MountBisSystemProperPartition = 0x10, + MountSdCard = 0x11, + MountGameCard = 0x12, + MountDeviceSaveData = 0x13, + MountSystemSaveData = 0x14, + MountOthersSaveData = 0x15, + MountOthersSystemSaveData = 0x16, + OpenBisPartitionBootPartition1Root = 0x17, + OpenBisPartitionBootPartition2Root = 0x18, + OpenBisPartitionUserDataRoot = 0x19, + OpenBisPartitionBootConfigAndPackage2Part1 = 0x1A, + OpenBisPartitionBootConfigAndPackage2Part2 = 0x1B, + OpenBisPartitionBootConfigAndPackage2Part3 = 0x1C, + OpenBisPartitionBootConfigAndPackage2Part4 = 0x1D, + OpenBisPartitionBootConfigAndPackage2Part5 = 0x1E, + OpenBisPartitionBootConfigAndPackage2Part6 = 0x1F, + OpenBisPartitionCalibrationBinary = 0x20, + OpenBisPartitionCalibrationFile = 0x21, + OpenBisPartitionSafeMode = 0x22, + OpenBisPartitionUser = 0x23, + OpenBisPartitionSystem = 0x24, + OpenBisPartitionSystemProperEncryption = 0x25, + OpenBisPartitionSystemProperPartition = 0x26, + OpenSdCardStorage = 0x27, + OpenGameCardStorage = 0x28, + MountSystemDataPrivate = 0x29, + MountHost = 0x2A, + MountRegisteredUpdatePartition = 0x2B, + MountSaveDataInternalStorage = 0x2C, + NotMountCustomStorage = 0x2D + } + + /// + /// Permissions that control which actions can be performed. + /// + public enum ActionPermissions + { + // Todo + } + + public static class PermissionUtils + { + public static ulong GetPermissionMask(AccessPermissions id) + { + switch (id) + { + case AccessPermissions.MountLogo: + return 0x8000000000000801; + case AccessPermissions.MountContentMeta: + return 0x8000000000000801; + case AccessPermissions.MountContentControl: + return 0x8000000000000801; + case AccessPermissions.MountContentManual: + return 0x8000000000000801; + case AccessPermissions.MountContentData: + return 0x8000000000000801; + case AccessPermissions.MountApplicationPackage: + return 0x8000000000000801; + case AccessPermissions.MountSaveDataStorage: + return 0x8000000000000000; + case AccessPermissions.MountContentStorage: + return 0x8000000000000800; + case AccessPermissions.MountImageAndVideoStorage: + return 0x8000000000001000; + case AccessPermissions.MountCloudBackupWorkStorage: + return 0x8000000200000000; + case AccessPermissions.MountCustomStorage: + return 0x8000000000000000; + case AccessPermissions.MountBisCalibrationFile: + return 0x8000000000000084; + case AccessPermissions.MountBisSafeMode: + return 0x8000000000000080; + case AccessPermissions.MountBisUser: + return 0x8000000000008080; + case AccessPermissions.MountBisSystem: + return 0x8000000000008080; + case AccessPermissions.MountBisSystemProperEncryption: + return 0x8000000000000080; + case AccessPermissions.MountBisSystemProperPartition: + return 0x8000000000000080; + case AccessPermissions.MountSdCard: + return 0xC000000000200000; + case AccessPermissions.MountGameCard: + return 0x8000000000000010; + case AccessPermissions.MountDeviceSaveData: + return 0x8000000000040020; + case AccessPermissions.MountSystemSaveData: + return 0x8000000000000028; + case AccessPermissions.MountOthersSaveData: + return 0x8000000000000020; + case AccessPermissions.MountOthersSystemSaveData: + return 0x8000000000000020; + case AccessPermissions.OpenBisPartitionBootPartition1Root: + return 0x8000000000010082; + case AccessPermissions.OpenBisPartitionBootPartition2Root: + return 0x8000000000010080; + case AccessPermissions.OpenBisPartitionUserDataRoot: + return 0x8000000000000080; + case AccessPermissions.OpenBisPartitionBootConfigAndPackage2Part1: + return 0x8000000000010080; + case AccessPermissions.OpenBisPartitionBootConfigAndPackage2Part2: + return 0x8000000000010080; + case AccessPermissions.OpenBisPartitionBootConfigAndPackage2Part3: + return 0x8000000000010080; + case AccessPermissions.OpenBisPartitionBootConfigAndPackage2Part4: + return 0x8000000000010080; + case AccessPermissions.OpenBisPartitionBootConfigAndPackage2Part5: + return 0x8000000000010080; + case AccessPermissions.OpenBisPartitionBootConfigAndPackage2Part6: + return 0x8000000000010080; + case AccessPermissions.OpenBisPartitionCalibrationBinary: + return 0x8000000000000084; + case AccessPermissions.OpenBisPartitionCalibrationFile: + return 0x8000000000000084; + case AccessPermissions.OpenBisPartitionSafeMode: + return 0x8000000000000080; + case AccessPermissions.OpenBisPartitionUser: + return 0x8000000000000080; + case AccessPermissions.OpenBisPartitionSystem: + return 0x8000000000000080; + case AccessPermissions.OpenBisPartitionSystemProperEncryption: + return 0x8000000000000080; + case AccessPermissions.OpenBisPartitionSystemProperPartition: + return 0x8000000000000080; + case AccessPermissions.OpenSdCardStorage: + return 0xC000000000200000; + case AccessPermissions.OpenGameCardStorage: + return 0x8000000000000100; + case AccessPermissions.MountSystemDataPrivate: + return 0x8000000000100008; + case AccessPermissions.MountHost: + return 0xC000000000400000; + case AccessPermissions.MountRegisteredUpdatePartition: + return 0x8000000000010000; + case AccessPermissions.MountSaveDataInternalStorage: + return 0x8000000000000000; + case AccessPermissions.NotMountCustomStorage: + return 0x0; + default: + throw new ArgumentOutOfRangeException(nameof(id), id, null); + } + } + } +} From 0e01aa3984ddafab23486ba7f19ee8b21f2331ae Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 21 Sep 2019 12:29:10 -0500 Subject: [PATCH 22/46] Rename FS namespaces --- src/LibHac/Cnmt.cs | 2 +- src/LibHac/Common/Id128.cs | 2 +- src/LibHac/Crypto.cs | 2 +- src/LibHac/{FsClient => Fs}/Accessors/DirectoryAccessor.cs | 4 ++-- src/LibHac/{FsClient => Fs}/Accessors/FileAccessor.cs | 4 ++-- src/LibHac/{FsClient => Fs}/Accessors/FileSystemAccessor.cs | 4 ++-- src/LibHac/{FsClient => Fs}/Accessors/MountTable.cs | 4 ++-- src/LibHac/{FsClient => Fs}/ContentStorage.cs | 4 ++-- src/LibHac/{FsClient => Fs}/DirectoryHandle.cs | 4 ++-- src/LibHac/{FsClient => Fs}/FileHandle.cs | 4 ++-- src/LibHac/{FsClient => Fs}/FileSystemClient.Directory.cs | 4 ++-- src/LibHac/{FsClient => Fs}/FileSystemClient.File.cs | 4 ++-- src/LibHac/{FsClient => Fs}/FileSystemClient.FileSystem.cs | 4 ++-- src/LibHac/{FsClient => Fs}/FileSystemClient.Mount.cs | 4 ++-- src/LibHac/{FsClient => Fs}/FileSystemClient.cs | 4 ++-- src/LibHac/{FsClient => Fs}/FileSystemManager.cs | 6 +++--- src/LibHac/{FsClient => Fs}/FileSystemManagerUtils.cs | 6 +++--- src/LibHac/{FsClient => Fs}/IAccessLog.cs | 2 +- src/LibHac/{FsClient => Fs}/ICommonMountNameGenerator.cs | 2 +- src/LibHac/{FsClient => Fs}/MountHelpers.cs | 4 ++-- src/LibHac/{FsClient => Fs}/SdCardAccessLog.cs | 2 +- .../FsService/Creators/EmulatedBisFileSystemCreator.cs | 2 +- .../Creators/EmulatedBisFileSystemCreatorConfig.cs | 2 +- .../FsService/Creators/EmulatedSdFileSystemCreator.cs | 2 +- src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs | 2 +- src/LibHac/FsService/Creators/FileSystemCreators.cs | 2 +- src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs | 2 +- .../FsService/Creators/IBuiltInStorageFileSystemCreator.cs | 2 +- .../FsService/Creators/IEncryptedFileSystemCreator.cs | 2 +- src/LibHac/FsService/Creators/IFatFileSystemCreator.cs | 2 +- src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs | 2 +- src/LibHac/FsService/Creators/IGameCardStorageCreator.cs | 2 +- src/LibHac/FsService/Creators/IHostFileSystemCreator.cs | 2 +- src/LibHac/FsService/Creators/IMemoryStorageCreator.cs | 2 +- .../FsService/Creators/IPartitionFileSystemCreator.cs | 2 +- src/LibHac/FsService/Creators/IRomFileSystemCreator.cs | 2 +- src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs | 4 ++-- src/LibHac/FsService/Creators/ISdFileSystemCreator.cs | 2 +- src/LibHac/FsService/Creators/ISdStorageCreator.cs | 2 +- src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs | 4 ++-- .../FsService/Creators/ISubDirectoryFileSystemCreator.cs | 2 +- .../FsService/Creators/ITargetManagerFileSystemCreator.cs | 2 +- .../FsService/Creators/SubDirectoryFileSystemCreator.cs | 2 +- src/LibHac/FsService/FileSystemProxy.cs | 2 +- src/LibHac/FsService/FileSystemProxyCore.cs | 4 ++-- src/LibHac/FsService/FileSystemServer.cs | 2 +- src/LibHac/FsService/IFileSystemProxy.cs | 2 +- src/LibHac/FsService/Util.cs | 2 +- src/LibHac/{Fs => FsSystem}/Aes128CtrExStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/Aes128CtrStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/Aes128CtrTransform.cs | 2 +- src/LibHac/{Fs => FsSystem}/Aes128XtsStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/Aes128XtsTransform.cs | 2 +- src/LibHac/{Fs => FsSystem}/AesXtsDirectory.cs | 2 +- src/LibHac/{Fs => FsSystem}/AesXtsFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/AesXtsFileHeader.cs | 2 +- src/LibHac/{Fs => FsSystem}/AesXtsFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/BucketTree.cs | 2 +- src/LibHac/{Fs => FsSystem}/CachedStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/ConcatenationDirectory.cs | 2 +- src/LibHac/{Fs => FsSystem}/ConcatenationFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/ConcatenationFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/ConcatenationStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/ConcatenationStorageBuilder.cs | 2 +- src/LibHac/{Fs => FsSystem}/Delta.cs | 2 +- src/LibHac/{Fs => FsSystem}/DirectoryEntry.cs | 2 +- src/LibHac/{Fs => FsSystem}/DirectorySaveDataFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/DirectorySaveDataFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/DirectoryUtils.cs | 2 +- src/LibHac/{Fs => FsSystem}/FileBase.cs | 2 +- src/LibHac/{Fs => FsSystem}/FileReader.cs | 2 +- src/LibHac/{Fs => FsSystem}/FileStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/FileSystemExtensions.cs | 2 +- src/LibHac/{Fs => FsSystem}/FileTimeStamp.cs | 2 +- src/LibHac/{Fs => FsSystem}/FsEnums.cs | 2 +- src/LibHac/{Fs => FsSystem}/FsPath.cs | 2 +- .../HierarchicalIntegrityVerificationStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/IAttributeFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/IDirectory.cs | 2 +- src/LibHac/{Fs => FsSystem}/IFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/IFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/IStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/IndirectStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/IntegrityVerificationStorage.cs | 4 ++-- src/LibHac/{Fs => FsSystem}/LayeredFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/LayeredFileSystemDirectory.cs | 2 +- src/LibHac/{Fs => FsSystem}/LocalDirectory.cs | 2 +- src/LibHac/{Fs => FsSystem}/LocalFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/LocalFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/LocalStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/MemoryStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/Messages.cs | 2 +- src/LibHac/{Fs => FsSystem}/NcaUtils/Nca.cs | 4 ++-- src/LibHac/{Fs => FsSystem}/NcaUtils/NcaExtensions.cs | 2 +- src/LibHac/{Fs => FsSystem}/NcaUtils/NcaFsHeader.cs | 2 +- .../{Fs => FsSystem}/NcaUtils/NcaFsIntegrityInfoIvfc.cs | 2 +- .../{Fs => FsSystem}/NcaUtils/NcaFsIntegrityInfoSha256.cs | 2 +- src/LibHac/{Fs => FsSystem}/NcaUtils/NcaFsPatchInfo.cs | 2 +- src/LibHac/{Fs => FsSystem}/NcaUtils/NcaHeader.cs | 2 +- src/LibHac/{Fs => FsSystem}/NcaUtils/NcaKeyType.cs | 2 +- src/LibHac/{Fs => FsSystem}/NcaUtils/NcaStructs.cs | 2 +- src/LibHac/{Fs => FsSystem}/NullFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/NullStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/NxFileStream.cs | 2 +- src/LibHac/{Fs => FsSystem}/PartitionDirectory.cs | 2 +- src/LibHac/{Fs => FsSystem}/PartitionFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/PartitionFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/PartitionFileSystemBuilder.cs | 2 +- src/LibHac/{Fs => FsSystem}/PathParser.cs | 2 +- src/LibHac/{Fs => FsSystem}/PathTools.cs | 2 +- src/LibHac/{Fs => FsSystem}/ReadOnlyFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/ReadOnlyFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/ResultFs.cs | 2 +- src/LibHac/{Fs => FsSystem}/ResultRangeFs.cs | 2 +- src/LibHac/{Fs => FsSystem}/RightsId.cs | 2 +- .../{Fs => FsSystem}/RomFs/HierarchicalRomFileTable.cs | 2 +- src/LibHac/{Fs => FsSystem}/RomFs/RomFsBuilder.cs | 2 +- src/LibHac/{Fs => FsSystem}/RomFs/RomFsDictionary.cs | 2 +- src/LibHac/{Fs => FsSystem}/RomFs/RomFsDirectory.cs | 2 +- src/LibHac/{Fs => FsSystem}/RomFs/RomFsEntries.cs | 2 +- src/LibHac/{Fs => FsSystem}/RomFs/RomFsFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/RomFs/RomFsFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/AllocationTable.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/AllocationTableIterator.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/AllocationTableStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/DuplexBitmap.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/DuplexStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/Header.cs | 2 +- .../{Fs => FsSystem}/Save/HierarchicalDuplexStorage.cs | 2 +- .../{Fs => FsSystem}/Save/HierarchicalSaveFileTable.cs | 2 +- .../{Fs => FsSystem}/Save/ISaveDataExtraDataAccessor.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/JournalMap.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/JournalStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/RemapStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/SaveDataDirectory.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/SaveDataFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/SaveDataFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/SaveDataFileSystemCore.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/SaveExtensions.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/SaveFsEntry.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/SaveFsList.cs | 2 +- src/LibHac/{Fs => FsSystem}/Save/SaveResults.cs | 2 +- src/LibHac/{Fs => FsSystem}/SaveDataAttribute.cs | 4 ++-- src/LibHac/{Fs => FsSystem}/SaveDataCreateInfo.cs | 2 +- src/LibHac/{Fs => FsSystem}/SaveDataStructs.cs | 4 ++-- src/LibHac/{Fs => FsSystem}/SaveIndexerStruct.cs | 2 +- src/LibHac/{Fs => FsSystem}/SaveMetaCreateInfo.cs | 2 +- src/LibHac/{Fs => FsSystem}/SectorStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/StorageBase.cs | 2 +- src/LibHac/{Fs => FsSystem}/StorageExtensions.cs | 2 +- src/LibHac/{Fs => FsSystem}/StorageFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/StorageStream.cs | 2 +- src/LibHac/{Fs => FsSystem}/StreamFile.cs | 2 +- src/LibHac/{Fs => FsSystem}/StreamStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/SubStorage.cs | 2 +- src/LibHac/{Fs => FsSystem}/SubdirectoryFileSystem.cs | 2 +- src/LibHac/{Fs => FsSystem}/UserId.cs | 2 +- src/LibHac/{Fs => FsSystem}/ValueStringBuilder.cs | 2 +- src/LibHac/Horizon.cs | 2 +- src/LibHac/Keyset.cs | 2 +- src/LibHac/Kip.cs | 2 +- src/LibHac/Ncm/IContentStorage.cs | 2 +- src/LibHac/Nro.cs | 2 +- src/LibHac/Nso.cs | 2 +- src/LibHac/Package1.cs | 2 +- src/LibHac/Package2.cs | 2 +- src/LibHac/SwitchFs.cs | 6 +++--- src/LibHac/Xci.cs | 2 +- src/hactoolnet/AccessLog.cs | 2 +- src/hactoolnet/FsUtils.cs | 2 +- src/hactoolnet/Options.cs | 2 +- src/hactoolnet/Print.cs | 4 ++-- src/hactoolnet/ProcessBench.cs | 2 +- src/hactoolnet/ProcessDelta.cs | 4 ++-- src/hactoolnet/ProcessFsBuild.cs | 4 ++-- src/hactoolnet/ProcessKip.cs | 2 +- src/hactoolnet/ProcessNca.cs | 4 ++-- src/hactoolnet/ProcessPackage.cs | 2 +- src/hactoolnet/ProcessPfs.cs | 2 +- src/hactoolnet/ProcessRomfs.cs | 4 ++-- src/hactoolnet/ProcessSave.cs | 4 ++-- src/hactoolnet/ProcessSwitchFs.cs | 6 +++--- src/hactoolnet/ProcessXci.cs | 4 ++-- tests/LibHac.Tests/AesXts.cs | 2 +- tests/LibHac.Tests/PathToolsTests.cs | 2 +- tests/LibHac.Tests/RomFsTests.cs | 2 +- 186 files changed, 221 insertions(+), 221 deletions(-) rename src/LibHac/{FsClient => Fs}/Accessors/DirectoryAccessor.cs (96%) rename src/LibHac/{FsClient => Fs}/Accessors/FileAccessor.cs (98%) rename src/LibHac/{FsClient => Fs}/Accessors/FileSystemAccessor.cs (99%) rename src/LibHac/{FsClient => Fs}/Accessors/MountTable.cs (96%) rename src/LibHac/{FsClient => Fs}/ContentStorage.cs (98%) rename src/LibHac/{FsClient => Fs}/DirectoryHandle.cs (87%) rename src/LibHac/{FsClient => Fs}/FileHandle.cs (86%) rename src/LibHac/{FsClient => Fs}/FileSystemClient.Directory.cs (93%) rename src/LibHac/{FsClient => Fs}/FileSystemClient.File.cs (97%) rename src/LibHac/{FsClient => Fs}/FileSystemClient.FileSystem.cs (98%) rename src/LibHac/{FsClient => Fs}/FileSystemClient.Mount.cs (93%) rename src/LibHac/{FsClient => Fs}/FileSystemClient.cs (96%) rename src/LibHac/{FsClient => Fs}/FileSystemManager.cs (99%) rename src/LibHac/{FsClient => Fs}/FileSystemManagerUtils.cs (99%) rename src/LibHac/{FsClient => Fs}/IAccessLog.cs (90%) rename src/LibHac/{FsClient => Fs}/ICommonMountNameGenerator.cs (83%) rename src/LibHac/{FsClient => Fs}/MountHelpers.cs (95%) rename src/LibHac/{FsClient => Fs}/SdCardAccessLog.cs (94%) rename src/LibHac/{Fs => FsSystem}/Aes128CtrExStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/Aes128CtrStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/Aes128CtrTransform.cs (98%) rename src/LibHac/{Fs => FsSystem}/Aes128XtsStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/Aes128XtsTransform.cs (99%) rename src/LibHac/{Fs => FsSystem}/AesXtsDirectory.cs (99%) rename src/LibHac/{Fs => FsSystem}/AesXtsFile.cs (99%) rename src/LibHac/{Fs => FsSystem}/AesXtsFileHeader.cs (99%) rename src/LibHac/{Fs => FsSystem}/AesXtsFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/BucketTree.cs (99%) rename src/LibHac/{Fs => FsSystem}/CachedStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/ConcatenationDirectory.cs (99%) rename src/LibHac/{Fs => FsSystem}/ConcatenationFile.cs (99%) rename src/LibHac/{Fs => FsSystem}/ConcatenationFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/ConcatenationStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/ConcatenationStorageBuilder.cs (98%) rename src/LibHac/{Fs => FsSystem}/Delta.cs (99%) rename src/LibHac/{Fs => FsSystem}/DirectoryEntry.cs (97%) rename src/LibHac/{Fs => FsSystem}/DirectorySaveDataFile.cs (98%) rename src/LibHac/{Fs => FsSystem}/DirectorySaveDataFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/DirectoryUtils.cs (99%) rename src/LibHac/{Fs => FsSystem}/FileBase.cs (99%) rename src/LibHac/{Fs => FsSystem}/FileReader.cs (99%) rename src/LibHac/{Fs => FsSystem}/FileStorage.cs (97%) rename src/LibHac/{Fs => FsSystem}/FileSystemExtensions.cs (99%) rename src/LibHac/{Fs => FsSystem}/FileTimeStamp.cs (82%) rename src/LibHac/{Fs => FsSystem}/FsEnums.cs (98%) rename src/LibHac/{Fs => FsSystem}/FsPath.cs (95%) rename src/LibHac/{Fs => FsSystem}/HierarchicalIntegrityVerificationStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/IAttributeFileSystem.cs (89%) rename src/LibHac/{Fs => FsSystem}/IDirectory.cs (98%) rename src/LibHac/{Fs => FsSystem}/IFile.cs (99%) rename src/LibHac/{Fs => FsSystem}/IFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/IStorage.cs (98%) rename src/LibHac/{Fs => FsSystem}/IndirectStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/IntegrityVerificationStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/LayeredFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/LayeredFileSystemDirectory.cs (98%) rename src/LibHac/{Fs => FsSystem}/LocalDirectory.cs (99%) rename src/LibHac/{Fs => FsSystem}/LocalFile.cs (99%) rename src/LibHac/{Fs => FsSystem}/LocalFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/LocalStorage.cs (97%) rename src/LibHac/{Fs => FsSystem}/MemoryStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/Messages.cs (95%) rename src/LibHac/{Fs => FsSystem}/NcaUtils/Nca.cs (99%) rename src/LibHac/{Fs => FsSystem}/NcaUtils/NcaExtensions.cs (99%) rename src/LibHac/{Fs => FsSystem}/NcaUtils/NcaFsHeader.cs (98%) rename src/LibHac/{Fs => FsSystem}/NcaUtils/NcaFsIntegrityInfoIvfc.cs (98%) rename src/LibHac/{Fs => FsSystem}/NcaUtils/NcaFsIntegrityInfoSha256.cs (98%) rename src/LibHac/{Fs => FsSystem}/NcaUtils/NcaFsPatchInfo.cs (97%) rename src/LibHac/{Fs => FsSystem}/NcaUtils/NcaHeader.cs (99%) rename src/LibHac/{Fs => FsSystem}/NcaUtils/NcaKeyType.cs (76%) rename src/LibHac/{Fs => FsSystem}/NcaUtils/NcaStructs.cs (97%) rename src/LibHac/{Fs => FsSystem}/NullFile.cs (97%) rename src/LibHac/{Fs => FsSystem}/NullStorage.cs (97%) rename src/LibHac/{Fs => FsSystem}/NxFileStream.cs (98%) rename src/LibHac/{Fs => FsSystem}/PartitionDirectory.cs (98%) rename src/LibHac/{Fs => FsSystem}/PartitionFile.cs (98%) rename src/LibHac/{Fs => FsSystem}/PartitionFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/PartitionFileSystemBuilder.cs (99%) rename src/LibHac/{Fs => FsSystem}/PathParser.cs (99%) rename src/LibHac/{Fs => FsSystem}/PathTools.cs (99%) rename src/LibHac/{Fs => FsSystem}/ReadOnlyFile.cs (97%) rename src/LibHac/{Fs => FsSystem}/ReadOnlyFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/ResultFs.cs (99%) rename src/LibHac/{Fs => FsSystem}/ResultRangeFs.cs (97%) rename src/LibHac/{Fs => FsSystem}/RightsId.cs (98%) rename src/LibHac/{Fs => FsSystem}/RomFs/HierarchicalRomFileTable.cs (99%) rename src/LibHac/{Fs => FsSystem}/RomFs/RomFsBuilder.cs (99%) rename src/LibHac/{Fs => FsSystem}/RomFs/RomFsDictionary.cs (99%) rename src/LibHac/{Fs => FsSystem}/RomFs/RomFsDirectory.cs (98%) rename src/LibHac/{Fs => FsSystem}/RomFs/RomFsEntries.cs (97%) rename src/LibHac/{Fs => FsSystem}/RomFs/RomFsFile.cs (97%) rename src/LibHac/{Fs => FsSystem}/RomFs/RomFsFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/AllocationTable.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/AllocationTableIterator.cs (98%) rename src/LibHac/{Fs => FsSystem}/Save/AllocationTableStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/DuplexBitmap.cs (97%) rename src/LibHac/{Fs => FsSystem}/Save/DuplexStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/Header.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/HierarchicalDuplexStorage.cs (98%) rename src/LibHac/{Fs => FsSystem}/Save/HierarchicalSaveFileTable.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/ISaveDataExtraDataAccessor.cs (83%) rename src/LibHac/{Fs => FsSystem}/Save/JournalMap.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/JournalStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/RemapStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/SaveDataDirectory.cs (98%) rename src/LibHac/{Fs => FsSystem}/Save/SaveDataFile.cs (98%) rename src/LibHac/{Fs => FsSystem}/Save/SaveDataFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/SaveDataFileSystemCore.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/SaveExtensions.cs (93%) rename src/LibHac/{Fs => FsSystem}/Save/SaveFsEntry.cs (96%) rename src/LibHac/{Fs => FsSystem}/Save/SaveFsList.cs (99%) rename src/LibHac/{Fs => FsSystem}/Save/SaveResults.cs (99%) rename src/LibHac/{Fs => FsSystem}/SaveDataAttribute.cs (98%) rename src/LibHac/{Fs => FsSystem}/SaveDataCreateInfo.cs (86%) rename src/LibHac/{Fs => FsSystem}/SaveDataStructs.cs (97%) rename src/LibHac/{Fs => FsSystem}/SaveIndexerStruct.cs (98%) rename src/LibHac/{Fs => FsSystem}/SaveMetaCreateInfo.cs (90%) rename src/LibHac/{Fs => FsSystem}/SectorStorage.cs (98%) rename src/LibHac/{Fs => FsSystem}/StorageBase.cs (98%) rename src/LibHac/{Fs => FsSystem}/StorageExtensions.cs (99%) rename src/LibHac/{Fs => FsSystem}/StorageFile.cs (98%) rename src/LibHac/{Fs => FsSystem}/StorageStream.cs (98%) rename src/LibHac/{Fs => FsSystem}/StreamFile.cs (99%) rename src/LibHac/{Fs => FsSystem}/StreamStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/SubStorage.cs (99%) rename src/LibHac/{Fs => FsSystem}/SubdirectoryFileSystem.cs (99%) rename src/LibHac/{Fs => FsSystem}/UserId.cs (98%) rename src/LibHac/{Fs => FsSystem}/ValueStringBuilder.cs (99%) diff --git a/src/LibHac/Cnmt.cs b/src/LibHac/Cnmt.cs index e6869390..b5616af3 100644 --- a/src/LibHac/Cnmt.cs +++ b/src/LibHac/Cnmt.cs @@ -1,6 +1,6 @@ using System.IO; using System.Linq; -using LibHac.Fs.NcaUtils; +using LibHac.FsSystem.NcaUtils; using LibHac.Ncm; using ContentType = LibHac.Ncm.ContentType; diff --git a/src/LibHac/Common/Id128.cs b/src/LibHac/Common/Id128.cs index 68deec6c..8b7f8529 100644 --- a/src/LibHac/Common/Id128.cs +++ b/src/LibHac/Common/Id128.cs @@ -35,7 +35,7 @@ namespace LibHac.Common public override bool Equals(object obj) { - return obj is Fs.UserId other && Equals(other); + return obj is FsSystem.UserId other && Equals(other); } public override int GetHashCode() diff --git a/src/LibHac/Crypto.cs b/src/LibHac/Crypto.cs index 3ae39d49..62c859ba 100644 --- a/src/LibHac/Crypto.cs +++ b/src/LibHac/Crypto.cs @@ -2,7 +2,7 @@ using System.IO; using System.Numerics; using System.Security.Cryptography; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac { diff --git a/src/LibHac/FsClient/Accessors/DirectoryAccessor.cs b/src/LibHac/Fs/Accessors/DirectoryAccessor.cs similarity index 96% rename from src/LibHac/FsClient/Accessors/DirectoryAccessor.cs rename to src/LibHac/Fs/Accessors/DirectoryAccessor.cs index 86eed8ed..75cf7b25 100644 --- a/src/LibHac/FsClient/Accessors/DirectoryAccessor.cs +++ b/src/LibHac/Fs/Accessors/DirectoryAccessor.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using LibHac.Fs; +using LibHac.FsSystem; -namespace LibHac.FsClient.Accessors +namespace LibHac.Fs.Accessors { public class DirectoryAccessor : IDisposable { diff --git a/src/LibHac/FsClient/Accessors/FileAccessor.cs b/src/LibHac/Fs/Accessors/FileAccessor.cs similarity index 98% rename from src/LibHac/FsClient/Accessors/FileAccessor.cs rename to src/LibHac/Fs/Accessors/FileAccessor.cs index 9624c6ec..d6ef410f 100644 --- a/src/LibHac/FsClient/Accessors/FileAccessor.cs +++ b/src/LibHac/Fs/Accessors/FileAccessor.cs @@ -1,7 +1,7 @@ using System; -using LibHac.Fs; +using LibHac.FsSystem; -namespace LibHac.FsClient.Accessors +namespace LibHac.Fs.Accessors { public class FileAccessor : IFile { diff --git a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs b/src/LibHac/Fs/Accessors/FileSystemAccessor.cs similarity index 99% rename from src/LibHac/FsClient/Accessors/FileSystemAccessor.cs rename to src/LibHac/Fs/Accessors/FileSystemAccessor.cs index a52fe3c2..f89b4d61 100644 --- a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs +++ b/src/LibHac/Fs/Accessors/FileSystemAccessor.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using LibHac.Fs; +using LibHac.FsSystem; -namespace LibHac.FsClient.Accessors +namespace LibHac.Fs.Accessors { public class FileSystemAccessor { diff --git a/src/LibHac/FsClient/Accessors/MountTable.cs b/src/LibHac/Fs/Accessors/MountTable.cs similarity index 96% rename from src/LibHac/FsClient/Accessors/MountTable.cs rename to src/LibHac/Fs/Accessors/MountTable.cs index de87b56e..06469eab 100644 --- a/src/LibHac/FsClient/Accessors/MountTable.cs +++ b/src/LibHac/Fs/Accessors/MountTable.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using LibHac.Fs; +using LibHac.FsSystem; -namespace LibHac.FsClient.Accessors +namespace LibHac.Fs.Accessors { public class MountTable { diff --git a/src/LibHac/FsClient/ContentStorage.cs b/src/LibHac/Fs/ContentStorage.cs similarity index 98% rename from src/LibHac/FsClient/ContentStorage.cs rename to src/LibHac/Fs/ContentStorage.cs index a84137aa..25a8da2a 100644 --- a/src/LibHac/FsClient/ContentStorage.cs +++ b/src/LibHac/Fs/ContentStorage.cs @@ -1,9 +1,9 @@ using System; using LibHac.Common; -using LibHac.Fs; +using LibHac.FsSystem; using LibHac.FsService; -namespace LibHac.FsClient +namespace LibHac.Fs { public static class ContentStorage { diff --git a/src/LibHac/FsClient/DirectoryHandle.cs b/src/LibHac/Fs/DirectoryHandle.cs similarity index 87% rename from src/LibHac/FsClient/DirectoryHandle.cs rename to src/LibHac/Fs/DirectoryHandle.cs index cab42040..e76ac017 100644 --- a/src/LibHac/FsClient/DirectoryHandle.cs +++ b/src/LibHac/Fs/DirectoryHandle.cs @@ -1,7 +1,7 @@ using System; -using LibHac.FsClient.Accessors; +using LibHac.Fs.Accessors; -namespace LibHac.FsClient +namespace LibHac.Fs { public struct DirectoryHandle : IDisposable { diff --git a/src/LibHac/FsClient/FileHandle.cs b/src/LibHac/Fs/FileHandle.cs similarity index 86% rename from src/LibHac/FsClient/FileHandle.cs rename to src/LibHac/Fs/FileHandle.cs index 0c728291..acb4e211 100644 --- a/src/LibHac/FsClient/FileHandle.cs +++ b/src/LibHac/Fs/FileHandle.cs @@ -1,7 +1,7 @@ using System; -using LibHac.FsClient.Accessors; +using LibHac.Fs.Accessors; -namespace LibHac.FsClient +namespace LibHac.Fs { public struct FileHandle : IDisposable { diff --git a/src/LibHac/FsClient/FileSystemClient.Directory.cs b/src/LibHac/Fs/FileSystemClient.Directory.cs similarity index 93% rename from src/LibHac/FsClient/FileSystemClient.Directory.cs rename to src/LibHac/Fs/FileSystemClient.Directory.cs index 61b9151d..6d29c054 100644 --- a/src/LibHac/FsClient/FileSystemClient.Directory.cs +++ b/src/LibHac/Fs/FileSystemClient.Directory.cs @@ -1,7 +1,7 @@ using System; -using LibHac.Fs; +using LibHac.FsSystem; -namespace LibHac.FsClient +namespace LibHac.Fs { public partial class FileSystemClient { diff --git a/src/LibHac/FsClient/FileSystemClient.File.cs b/src/LibHac/Fs/FileSystemClient.File.cs similarity index 97% rename from src/LibHac/FsClient/FileSystemClient.File.cs rename to src/LibHac/Fs/FileSystemClient.File.cs index 51a6b4dd..82ae189b 100644 --- a/src/LibHac/FsClient/FileSystemClient.File.cs +++ b/src/LibHac/Fs/FileSystemClient.File.cs @@ -1,7 +1,7 @@ using System; -using LibHac.Fs; +using LibHac.FsSystem; -namespace LibHac.FsClient +namespace LibHac.Fs { public partial class FileSystemClient { diff --git a/src/LibHac/FsClient/FileSystemClient.FileSystem.cs b/src/LibHac/Fs/FileSystemClient.FileSystem.cs similarity index 98% rename from src/LibHac/FsClient/FileSystemClient.FileSystem.cs rename to src/LibHac/Fs/FileSystemClient.FileSystem.cs index a0f6bd2e..e701a656 100644 --- a/src/LibHac/FsClient/FileSystemClient.FileSystem.cs +++ b/src/LibHac/Fs/FileSystemClient.FileSystem.cs @@ -1,6 +1,6 @@ -using LibHac.Fs; +using LibHac.FsSystem; -namespace LibHac.FsClient +namespace LibHac.Fs { public partial class FileSystemClient { diff --git a/src/LibHac/FsClient/FileSystemClient.Mount.cs b/src/LibHac/Fs/FileSystemClient.Mount.cs similarity index 93% rename from src/LibHac/FsClient/FileSystemClient.Mount.cs rename to src/LibHac/Fs/FileSystemClient.Mount.cs index e98044d6..0ccb6440 100644 --- a/src/LibHac/FsClient/FileSystemClient.Mount.cs +++ b/src/LibHac/Fs/FileSystemClient.Mount.cs @@ -1,8 +1,8 @@ using LibHac.Common; -using LibHac.Fs; +using LibHac.FsSystem; using LibHac.FsService; -namespace LibHac.FsClient +namespace LibHac.Fs { public partial class FileSystemClient { diff --git a/src/LibHac/FsClient/FileSystemClient.cs b/src/LibHac/Fs/FileSystemClient.cs similarity index 96% rename from src/LibHac/FsClient/FileSystemClient.cs rename to src/LibHac/Fs/FileSystemClient.cs index 8bc0a42a..3c4f5ff9 100644 --- a/src/LibHac/FsClient/FileSystemClient.cs +++ b/src/LibHac/Fs/FileSystemClient.cs @@ -1,8 +1,8 @@ using LibHac.Common; -using LibHac.Fs; +using LibHac.FsSystem; using LibHac.FsService; -namespace LibHac.FsClient +namespace LibHac.Fs { public partial class FileSystemClient { diff --git a/src/LibHac/FsClient/FileSystemManager.cs b/src/LibHac/Fs/FileSystemManager.cs similarity index 99% rename from src/LibHac/FsClient/FileSystemManager.cs rename to src/LibHac/Fs/FileSystemManager.cs index 45e2c4fc..29e33b55 100644 --- a/src/LibHac/FsClient/FileSystemManager.cs +++ b/src/LibHac/Fs/FileSystemManager.cs @@ -1,10 +1,10 @@ using System; using System.Runtime.CompilerServices; using LibHac.Common; -using LibHac.Fs; -using LibHac.FsClient.Accessors; +using LibHac.Fs.Accessors; +using LibHac.FsSystem; -namespace LibHac.FsClient +namespace LibHac.Fs { // Todo: Access log for FindFileSystem public class FileSystemManager diff --git a/src/LibHac/FsClient/FileSystemManagerUtils.cs b/src/LibHac/Fs/FileSystemManagerUtils.cs similarity index 99% rename from src/LibHac/FsClient/FileSystemManagerUtils.cs rename to src/LibHac/Fs/FileSystemManagerUtils.cs index eb2add2c..4aa01e30 100644 --- a/src/LibHac/FsClient/FileSystemManagerUtils.cs +++ b/src/LibHac/Fs/FileSystemManagerUtils.cs @@ -2,10 +2,10 @@ using System.Buffers; using System.Collections.Generic; using LibHac.Common; -using LibHac.Fs; -using LibHac.FsClient.Accessors; +using LibHac.Fs.Accessors; +using LibHac.FsSystem; -namespace LibHac.FsClient +namespace LibHac.Fs { public static class FileSystemManagerUtils { diff --git a/src/LibHac/FsClient/IAccessLog.cs b/src/LibHac/Fs/IAccessLog.cs similarity index 90% rename from src/LibHac/FsClient/IAccessLog.cs rename to src/LibHac/Fs/IAccessLog.cs index fbf83d5a..6ad9f3ca 100644 --- a/src/LibHac/FsClient/IAccessLog.cs +++ b/src/LibHac/Fs/IAccessLog.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.CompilerServices; -namespace LibHac.FsClient +namespace LibHac.Fs { public interface IAccessLog { diff --git a/src/LibHac/FsClient/ICommonMountNameGenerator.cs b/src/LibHac/Fs/ICommonMountNameGenerator.cs similarity index 83% rename from src/LibHac/FsClient/ICommonMountNameGenerator.cs rename to src/LibHac/Fs/ICommonMountNameGenerator.cs index 937c58d2..53838931 100644 --- a/src/LibHac/FsClient/ICommonMountNameGenerator.cs +++ b/src/LibHac/Fs/ICommonMountNameGenerator.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.FsClient +namespace LibHac.Fs { public interface ICommonMountNameGenerator { diff --git a/src/LibHac/FsClient/MountHelpers.cs b/src/LibHac/Fs/MountHelpers.cs similarity index 95% rename from src/LibHac/FsClient/MountHelpers.cs rename to src/LibHac/Fs/MountHelpers.cs index 18799d41..5d46e223 100644 --- a/src/LibHac/FsClient/MountHelpers.cs +++ b/src/LibHac/Fs/MountHelpers.cs @@ -1,7 +1,7 @@ using LibHac.Common; -using LibHac.Fs; +using LibHac.FsSystem; -namespace LibHac.FsClient +namespace LibHac.Fs { internal static class MountHelpers { diff --git a/src/LibHac/FsClient/SdCardAccessLog.cs b/src/LibHac/Fs/SdCardAccessLog.cs similarity index 94% rename from src/LibHac/FsClient/SdCardAccessLog.cs rename to src/LibHac/Fs/SdCardAccessLog.cs index a69dc12a..345e64c2 100644 --- a/src/LibHac/FsClient/SdCardAccessLog.cs +++ b/src/LibHac/Fs/SdCardAccessLog.cs @@ -1,7 +1,7 @@ using System; using LibHac.FsService; -namespace LibHac.FsClient +namespace LibHac.Fs { /// /// The default access logger that will output to the SD card via . diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs index edba44ca..9ba8578a 100644 --- a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs @@ -1,5 +1,5 @@ using System.Diagnostics; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs index 1e6ebe98..0fd195ab 100644 --- a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs @@ -1,5 +1,5 @@ using System.Diagnostics; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs index b27c6aff..b5392d4f 100644 --- a/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs @@ -1,5 +1,5 @@ using System; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs b/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs index 81d5dc4b..b1798719 100644 --- a/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs @@ -1,5 +1,5 @@ using System; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/FileSystemCreators.cs b/src/LibHac/FsService/Creators/FileSystemCreators.cs index 2afa63df..0539a95c 100644 --- a/src/LibHac/FsService/Creators/FileSystemCreators.cs +++ b/src/LibHac/FsService/Creators/FileSystemCreators.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs b/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs index e7e6df62..397da7ef 100644 --- a/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs +++ b/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs b/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs index b94ca90a..07c4b68d 100644 --- a/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs b/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs index f6cfde96..36f73579 100644 --- a/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs @@ -1,5 +1,5 @@ using System; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs b/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs index b86fac56..8b139d5c 100644 --- a/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs b/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs index 550ce9c6..c57357dd 100644 --- a/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs b/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs index e5fdfc19..b6afd9e5 100644 --- a/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs +++ b/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs index d7c50ff5..809fbef0 100644 --- a/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs b/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs index 403dbe01..14b0e961 100644 --- a/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs +++ b/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs @@ -1,5 +1,5 @@ using System; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs b/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs index af99e8cd..d6b43d6b 100644 --- a/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs b/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs index b2ea3957..3429397f 100644 --- a/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs index 335d65e2..854fb051 100644 --- a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs @@ -1,7 +1,7 @@ using System; using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Save; +using LibHac.FsSystem; +using LibHac.FsSystem.Save; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs index 041f0217..0a0765dc 100644 --- a/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/ISdStorageCreator.cs b/src/LibHac/FsService/Creators/ISdStorageCreator.cs index 691359bb..bb2c2dac 100644 --- a/src/LibHac/FsService/Creators/ISdStorageCreator.cs +++ b/src/LibHac/FsService/Creators/ISdStorageCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs b/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs index 4c76e12a..92378a75 100644 --- a/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs +++ b/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs @@ -1,5 +1,5 @@ -using LibHac.Fs; -using LibHac.Fs.NcaUtils; +using LibHac.FsSystem; +using LibHac.FsSystem.NcaUtils; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs index 3bae3cb7..1ac8a48a 100644 --- a/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs index e0858de4..59eed39a 100644 --- a/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs index ad2ecf8b..fed3898c 100644 --- a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index 4449c91a..a015e579 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -1,7 +1,7 @@ using System; using LibHac.Common; using LibHac.Fs; -using LibHac.FsClient; +using LibHac.FsSystem; namespace LibHac.FsService { diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 58250891..8463c2a3 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -1,6 +1,6 @@ using System; -using LibHac.Fs; -using LibHac.Fs.Save; +using LibHac.FsSystem; +using LibHac.FsSystem.Save; using LibHac.FsService.Creators; namespace LibHac.FsService diff --git a/src/LibHac/FsService/FileSystemServer.cs b/src/LibHac/FsService/FileSystemServer.cs index 974a8f34..849ba674 100644 --- a/src/LibHac/FsService/FileSystemServer.cs +++ b/src/LibHac/FsService/FileSystemServer.cs @@ -1,4 +1,4 @@ -using LibHac.FsClient; +using LibHac.Fs; using LibHac.FsService.Creators; namespace LibHac.FsService diff --git a/src/LibHac/FsService/IFileSystemProxy.cs b/src/LibHac/FsService/IFileSystemProxy.cs index ffc4d3fb..708d3155 100644 --- a/src/LibHac/FsService/IFileSystemProxy.cs +++ b/src/LibHac/FsService/IFileSystemProxy.cs @@ -1,6 +1,6 @@ using System; using LibHac.Common; -using LibHac.Fs; +using LibHac.FsSystem; using LibHac.Ncm; using LibHac.Spl; diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs index b6ed2b2a..6519cf26 100644 --- a/src/LibHac/FsService/Util.cs +++ b/src/LibHac/FsService/Util.cs @@ -1,5 +1,5 @@ using System; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService { diff --git a/src/LibHac/Fs/Aes128CtrExStorage.cs b/src/LibHac/FsSystem/Aes128CtrExStorage.cs similarity index 99% rename from src/LibHac/Fs/Aes128CtrExStorage.cs rename to src/LibHac/FsSystem/Aes128CtrExStorage.cs index de3c327e..eebe24ff 100644 --- a/src/LibHac/Fs/Aes128CtrExStorage.cs +++ b/src/LibHac/FsSystem/Aes128CtrExStorage.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class Aes128CtrExStorage : Aes128CtrStorage { diff --git a/src/LibHac/Fs/Aes128CtrStorage.cs b/src/LibHac/FsSystem/Aes128CtrStorage.cs similarity index 99% rename from src/LibHac/Fs/Aes128CtrStorage.cs rename to src/LibHac/FsSystem/Aes128CtrStorage.cs index 99bb5a40..0437c092 100644 --- a/src/LibHac/Fs/Aes128CtrStorage.cs +++ b/src/LibHac/FsSystem/Aes128CtrStorage.cs @@ -2,7 +2,7 @@ using System.Buffers; using System.Buffers.Binary; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class Aes128CtrStorage : SectorStorage { diff --git a/src/LibHac/Fs/Aes128CtrTransform.cs b/src/LibHac/FsSystem/Aes128CtrTransform.cs similarity index 98% rename from src/LibHac/Fs/Aes128CtrTransform.cs rename to src/LibHac/FsSystem/Aes128CtrTransform.cs index 1a430e82..beaf2d7b 100644 --- a/src/LibHac/Fs/Aes128CtrTransform.cs +++ b/src/LibHac/FsSystem/Aes128CtrTransform.cs @@ -4,7 +4,7 @@ using System.Buffers.Binary; using System.Runtime.InteropServices; using System.Security.Cryptography; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class Aes128CtrTransform { diff --git a/src/LibHac/Fs/Aes128XtsStorage.cs b/src/LibHac/FsSystem/Aes128XtsStorage.cs similarity index 99% rename from src/LibHac/Fs/Aes128XtsStorage.cs rename to src/LibHac/FsSystem/Aes128XtsStorage.cs index 3187a8ce..a0844d61 100644 --- a/src/LibHac/Fs/Aes128XtsStorage.cs +++ b/src/LibHac/FsSystem/Aes128XtsStorage.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class Aes128XtsStorage : SectorStorage { diff --git a/src/LibHac/Fs/Aes128XtsTransform.cs b/src/LibHac/FsSystem/Aes128XtsTransform.cs similarity index 99% rename from src/LibHac/Fs/Aes128XtsTransform.cs rename to src/LibHac/FsSystem/Aes128XtsTransform.cs index 53aac4c6..9fc2eb55 100644 --- a/src/LibHac/Fs/Aes128XtsTransform.cs +++ b/src/LibHac/FsSystem/Aes128XtsTransform.cs @@ -29,7 +29,7 @@ using System.Buffers; using System.Runtime.InteropServices; using System.Security.Cryptography; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class Aes128XtsTransform { diff --git a/src/LibHac/Fs/AesXtsDirectory.cs b/src/LibHac/FsSystem/AesXtsDirectory.cs similarity index 99% rename from src/LibHac/Fs/AesXtsDirectory.cs rename to src/LibHac/FsSystem/AesXtsDirectory.cs index a8bd71cc..bb7d4415 100644 --- a/src/LibHac/Fs/AesXtsDirectory.cs +++ b/src/LibHac/FsSystem/AesXtsDirectory.cs @@ -1,7 +1,7 @@ using System; using LibHac.Common; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class AesXtsDirectory : IDirectory { diff --git a/src/LibHac/Fs/AesXtsFile.cs b/src/LibHac/FsSystem/AesXtsFile.cs similarity index 99% rename from src/LibHac/Fs/AesXtsFile.cs rename to src/LibHac/FsSystem/AesXtsFile.cs index fcaa6335..683c2341 100644 --- a/src/LibHac/Fs/AesXtsFile.cs +++ b/src/LibHac/FsSystem/AesXtsFile.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class AesXtsFile : FileBase { diff --git a/src/LibHac/Fs/AesXtsFileHeader.cs b/src/LibHac/FsSystem/AesXtsFileHeader.cs similarity index 99% rename from src/LibHac/Fs/AesXtsFileHeader.cs rename to src/LibHac/FsSystem/AesXtsFileHeader.cs index 292b39e0..da830f82 100644 --- a/src/LibHac/Fs/AesXtsFileHeader.cs +++ b/src/LibHac/FsSystem/AesXtsFileHeader.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class AesXtsFileHeader { diff --git a/src/LibHac/Fs/AesXtsFileSystem.cs b/src/LibHac/FsSystem/AesXtsFileSystem.cs similarity index 99% rename from src/LibHac/Fs/AesXtsFileSystem.cs rename to src/LibHac/FsSystem/AesXtsFileSystem.cs index 529e4c5b..fa33b06a 100644 --- a/src/LibHac/Fs/AesXtsFileSystem.cs +++ b/src/LibHac/FsSystem/AesXtsFileSystem.cs @@ -1,7 +1,7 @@ using System; using System.Diagnostics; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class AesXtsFileSystem : IFileSystem { diff --git a/src/LibHac/Fs/BucketTree.cs b/src/LibHac/FsSystem/BucketTree.cs similarity index 99% rename from src/LibHac/Fs/BucketTree.cs rename to src/LibHac/FsSystem/BucketTree.cs index 0c7cdb42..a9095a77 100644 --- a/src/LibHac/Fs/BucketTree.cs +++ b/src/LibHac/FsSystem/BucketTree.cs @@ -2,7 +2,7 @@ using System.IO; using System.Linq; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class BucketTree where T : BucketTreeEntry, new() { diff --git a/src/LibHac/Fs/CachedStorage.cs b/src/LibHac/FsSystem/CachedStorage.cs similarity index 99% rename from src/LibHac/Fs/CachedStorage.cs rename to src/LibHac/FsSystem/CachedStorage.cs index 964a4989..f73fffb2 100644 --- a/src/LibHac/Fs/CachedStorage.cs +++ b/src/LibHac/FsSystem/CachedStorage.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class CachedStorage : StorageBase { diff --git a/src/LibHac/Fs/ConcatenationDirectory.cs b/src/LibHac/FsSystem/ConcatenationDirectory.cs similarity index 99% rename from src/LibHac/Fs/ConcatenationDirectory.cs rename to src/LibHac/FsSystem/ConcatenationDirectory.cs index 88972e75..76587582 100644 --- a/src/LibHac/Fs/ConcatenationDirectory.cs +++ b/src/LibHac/FsSystem/ConcatenationDirectory.cs @@ -5,7 +5,7 @@ using LibHac.Common; using System.Runtime.InteropServices; #endif -namespace LibHac.Fs +namespace LibHac.FsSystem { public class ConcatenationDirectory : IDirectory { diff --git a/src/LibHac/Fs/ConcatenationFile.cs b/src/LibHac/FsSystem/ConcatenationFile.cs similarity index 99% rename from src/LibHac/Fs/ConcatenationFile.cs rename to src/LibHac/FsSystem/ConcatenationFile.cs index ad6842a8..887ac26a 100644 --- a/src/LibHac/Fs/ConcatenationFile.cs +++ b/src/LibHac/FsSystem/ConcatenationFile.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class ConcatenationFile : FileBase { diff --git a/src/LibHac/Fs/ConcatenationFileSystem.cs b/src/LibHac/FsSystem/ConcatenationFileSystem.cs similarity index 99% rename from src/LibHac/Fs/ConcatenationFileSystem.cs rename to src/LibHac/FsSystem/ConcatenationFileSystem.cs index b25f0f3e..c7c18686 100644 --- a/src/LibHac/Fs/ConcatenationFileSystem.cs +++ b/src/LibHac/FsSystem/ConcatenationFileSystem.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; #endif -namespace LibHac.Fs +namespace LibHac.FsSystem { /// /// An that stores large files as smaller, separate sub-files. diff --git a/src/LibHac/Fs/ConcatenationStorage.cs b/src/LibHac/FsSystem/ConcatenationStorage.cs similarity index 99% rename from src/LibHac/Fs/ConcatenationStorage.cs rename to src/LibHac/FsSystem/ConcatenationStorage.cs index af907d2f..7d695dc5 100644 --- a/src/LibHac/Fs/ConcatenationStorage.cs +++ b/src/LibHac/FsSystem/ConcatenationStorage.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class ConcatenationStorage : StorageBase { diff --git a/src/LibHac/Fs/ConcatenationStorageBuilder.cs b/src/LibHac/FsSystem/ConcatenationStorageBuilder.cs similarity index 98% rename from src/LibHac/Fs/ConcatenationStorageBuilder.cs rename to src/LibHac/FsSystem/ConcatenationStorageBuilder.cs index 86749565..ff2da7b8 100644 --- a/src/LibHac/Fs/ConcatenationStorageBuilder.cs +++ b/src/LibHac/FsSystem/ConcatenationStorageBuilder.cs @@ -2,7 +2,7 @@ using System.IO; using System.Linq; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class ConcatenationStorageBuilder { diff --git a/src/LibHac/Fs/Delta.cs b/src/LibHac/FsSystem/Delta.cs similarity index 99% rename from src/LibHac/Fs/Delta.cs rename to src/LibHac/FsSystem/Delta.cs index 3a70cdd7..9ca03cef 100644 --- a/src/LibHac/Fs/Delta.cs +++ b/src/LibHac/FsSystem/Delta.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class Delta { diff --git a/src/LibHac/Fs/DirectoryEntry.cs b/src/LibHac/FsSystem/DirectoryEntry.cs similarity index 97% rename from src/LibHac/Fs/DirectoryEntry.cs rename to src/LibHac/FsSystem/DirectoryEntry.cs index 62293fa7..332e4f6d 100644 --- a/src/LibHac/Fs/DirectoryEntry.cs +++ b/src/LibHac/FsSystem/DirectoryEntry.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using LibHac.Common; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class DirectoryEntryEx { diff --git a/src/LibHac/Fs/DirectorySaveDataFile.cs b/src/LibHac/FsSystem/DirectorySaveDataFile.cs similarity index 98% rename from src/LibHac/Fs/DirectorySaveDataFile.cs rename to src/LibHac/FsSystem/DirectorySaveDataFile.cs index 2c68ad92..62e384ce 100644 --- a/src/LibHac/Fs/DirectorySaveDataFile.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFile.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class DirectorySaveDataFile : FileBase { diff --git a/src/LibHac/Fs/DirectorySaveDataFileSystem.cs b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs similarity index 99% rename from src/LibHac/Fs/DirectorySaveDataFileSystem.cs rename to src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs index 70d74b54..a782dc2e 100644 --- a/src/LibHac/Fs/DirectorySaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class DirectorySaveDataFileSystem : IFileSystem { diff --git a/src/LibHac/Fs/DirectoryUtils.cs b/src/LibHac/FsSystem/DirectoryUtils.cs similarity index 99% rename from src/LibHac/Fs/DirectoryUtils.cs rename to src/LibHac/FsSystem/DirectoryUtils.cs index 1ea54ecc..b5bba902 100644 --- a/src/LibHac/Fs/DirectoryUtils.cs +++ b/src/LibHac/FsSystem/DirectoryUtils.cs @@ -1,7 +1,7 @@ using System; using LibHac.Common; -namespace LibHac.Fs +namespace LibHac.FsSystem { public static class DirectoryUtils { diff --git a/src/LibHac/Fs/FileBase.cs b/src/LibHac/FsSystem/FileBase.cs similarity index 99% rename from src/LibHac/Fs/FileBase.cs rename to src/LibHac/FsSystem/FileBase.cs index 1beff741..742853c2 100644 --- a/src/LibHac/Fs/FileBase.cs +++ b/src/LibHac/FsSystem/FileBase.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace LibHac.Fs +namespace LibHac.FsSystem { public abstract class FileBase : IFile { diff --git a/src/LibHac/Fs/FileReader.cs b/src/LibHac/FsSystem/FileReader.cs similarity index 99% rename from src/LibHac/Fs/FileReader.cs rename to src/LibHac/FsSystem/FileReader.cs index 25f54ea9..cf4607b4 100644 --- a/src/LibHac/Fs/FileReader.cs +++ b/src/LibHac/FsSystem/FileReader.cs @@ -3,7 +3,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class FileReader { diff --git a/src/LibHac/Fs/FileStorage.cs b/src/LibHac/FsSystem/FileStorage.cs similarity index 97% rename from src/LibHac/Fs/FileStorage.cs rename to src/LibHac/FsSystem/FileStorage.cs index 1b0ae864..21bf43c9 100644 --- a/src/LibHac/Fs/FileStorage.cs +++ b/src/LibHac/FsSystem/FileStorage.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class FileStorage : StorageBase { diff --git a/src/LibHac/Fs/FileSystemExtensions.cs b/src/LibHac/FsSystem/FileSystemExtensions.cs similarity index 99% rename from src/LibHac/Fs/FileSystemExtensions.cs rename to src/LibHac/FsSystem/FileSystemExtensions.cs index 35495263..9ed1571a 100644 --- a/src/LibHac/Fs/FileSystemExtensions.cs +++ b/src/LibHac/FsSystem/FileSystemExtensions.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.IO; using LibHac.Common; -namespace LibHac.Fs +namespace LibHac.FsSystem { public static class FileSystemExtensions { diff --git a/src/LibHac/Fs/FileTimeStamp.cs b/src/LibHac/FsSystem/FileTimeStamp.cs similarity index 82% rename from src/LibHac/Fs/FileTimeStamp.cs rename to src/LibHac/FsSystem/FileTimeStamp.cs index 74aff00a..0dbe64eb 100644 --- a/src/LibHac/Fs/FileTimeStamp.cs +++ b/src/LibHac/FsSystem/FileTimeStamp.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs +namespace LibHac.FsSystem { public struct FileTimeStampRaw { diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/FsSystem/FsEnums.cs similarity index 98% rename from src/LibHac/Fs/FsEnums.cs rename to src/LibHac/FsSystem/FsEnums.cs index 223f36fb..b00cf136 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/FsSystem/FsEnums.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs +namespace LibHac.FsSystem { public enum BisPartitionId { diff --git a/src/LibHac/Fs/FsPath.cs b/src/LibHac/FsSystem/FsPath.cs similarity index 95% rename from src/LibHac/Fs/FsPath.cs rename to src/LibHac/FsSystem/FsPath.cs index 4f10eb67..b40e5b60 100644 --- a/src/LibHac/Fs/FsPath.cs +++ b/src/LibHac/FsSystem/FsPath.cs @@ -3,7 +3,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using LibHac.Common; -namespace LibHac.Fs +namespace LibHac.FsSystem { [DebuggerDisplay("{ToString()}")] [StructLayout(LayoutKind.Explicit, Size = MaxLength + 1)] diff --git a/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs b/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs similarity index 99% rename from src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs rename to src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs index 92001edf..709eca51 100644 --- a/src/LibHac/Fs/HierarchicalIntegrityVerificationStorage.cs +++ b/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs @@ -4,7 +4,7 @@ using System.IO; using System.Security.Cryptography; using System.Text; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class HierarchicalIntegrityVerificationStorage : StorageBase { diff --git a/src/LibHac/Fs/IAttributeFileSystem.cs b/src/LibHac/FsSystem/IAttributeFileSystem.cs similarity index 89% rename from src/LibHac/Fs/IAttributeFileSystem.cs rename to src/LibHac/FsSystem/IAttributeFileSystem.cs index e5a4858d..e7688a1b 100644 --- a/src/LibHac/Fs/IAttributeFileSystem.cs +++ b/src/LibHac/FsSystem/IAttributeFileSystem.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs +namespace LibHac.FsSystem { public interface IAttributeFileSystem : IFileSystem { diff --git a/src/LibHac/Fs/IDirectory.cs b/src/LibHac/FsSystem/IDirectory.cs similarity index 98% rename from src/LibHac/Fs/IDirectory.cs rename to src/LibHac/FsSystem/IDirectory.cs index 401d26d7..d9355ec4 100644 --- a/src/LibHac/Fs/IDirectory.cs +++ b/src/LibHac/FsSystem/IDirectory.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { /// /// Provides an interface for enumerating the child entries of a directory. diff --git a/src/LibHac/Fs/IFile.cs b/src/LibHac/FsSystem/IFile.cs similarity index 99% rename from src/LibHac/Fs/IFile.cs rename to src/LibHac/FsSystem/IFile.cs index da2a5644..6e81af02 100644 --- a/src/LibHac/Fs/IFile.cs +++ b/src/LibHac/FsSystem/IFile.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { /// /// Provides an interface for reading and writing a sequence of bytes. diff --git a/src/LibHac/Fs/IFileSystem.cs b/src/LibHac/FsSystem/IFileSystem.cs similarity index 99% rename from src/LibHac/Fs/IFileSystem.cs rename to src/LibHac/FsSystem/IFileSystem.cs index 3d99bf3c..9ff76341 100644 --- a/src/LibHac/Fs/IFileSystem.cs +++ b/src/LibHac/FsSystem/IFileSystem.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { /// /// Provides an interface for accessing a file system. / is used as the path delimiter. diff --git a/src/LibHac/Fs/IStorage.cs b/src/LibHac/FsSystem/IStorage.cs similarity index 98% rename from src/LibHac/Fs/IStorage.cs rename to src/LibHac/FsSystem/IStorage.cs index 8f0a1b47..6f38528b 100644 --- a/src/LibHac/Fs/IStorage.cs +++ b/src/LibHac/FsSystem/IStorage.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { /// /// Provides an interface for reading and writing a sequence of bytes. diff --git a/src/LibHac/Fs/IndirectStorage.cs b/src/LibHac/FsSystem/IndirectStorage.cs similarity index 99% rename from src/LibHac/Fs/IndirectStorage.cs rename to src/LibHac/FsSystem/IndirectStorage.cs index f49336b0..850b401f 100644 --- a/src/LibHac/Fs/IndirectStorage.cs +++ b/src/LibHac/FsSystem/IndirectStorage.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class IndirectStorage : StorageBase { diff --git a/src/LibHac/Fs/IntegrityVerificationStorage.cs b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs similarity index 99% rename from src/LibHac/Fs/IntegrityVerificationStorage.cs rename to src/LibHac/FsSystem/IntegrityVerificationStorage.cs index 4adbab58..5e7bd8ce 100644 --- a/src/LibHac/Fs/IntegrityVerificationStorage.cs +++ b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs @@ -2,9 +2,9 @@ using System.Buffers; using System.IO; using System.Security.Cryptography; -using LibHac.Fs.Save; +using LibHac.FsSystem.Save; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class IntegrityVerificationStorage : SectorStorage { diff --git a/src/LibHac/Fs/LayeredFileSystem.cs b/src/LibHac/FsSystem/LayeredFileSystem.cs similarity index 99% rename from src/LibHac/Fs/LayeredFileSystem.cs rename to src/LibHac/FsSystem/LayeredFileSystem.cs index 329f7094..47e88d4a 100644 --- a/src/LibHac/Fs/LayeredFileSystem.cs +++ b/src/LibHac/FsSystem/LayeredFileSystem.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class LayeredFileSystem : IFileSystem { diff --git a/src/LibHac/Fs/LayeredFileSystemDirectory.cs b/src/LibHac/FsSystem/LayeredFileSystemDirectory.cs similarity index 98% rename from src/LibHac/Fs/LayeredFileSystemDirectory.cs rename to src/LibHac/FsSystem/LayeredFileSystemDirectory.cs index 9d1e31dc..3c23e239 100644 --- a/src/LibHac/Fs/LayeredFileSystemDirectory.cs +++ b/src/LibHac/FsSystem/LayeredFileSystemDirectory.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class LayeredFileSystemDirectory : IDirectory { diff --git a/src/LibHac/Fs/LocalDirectory.cs b/src/LibHac/FsSystem/LocalDirectory.cs similarity index 99% rename from src/LibHac/Fs/LocalDirectory.cs rename to src/LibHac/FsSystem/LocalDirectory.cs index bbce488d..02f478be 100644 --- a/src/LibHac/Fs/LocalDirectory.cs +++ b/src/LibHac/FsSystem/LocalDirectory.cs @@ -4,7 +4,7 @@ using System.IO; using System.Runtime.CompilerServices; using LibHac.Common; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class LocalDirectory : IDirectory { diff --git a/src/LibHac/Fs/LocalFile.cs b/src/LibHac/FsSystem/LocalFile.cs similarity index 99% rename from src/LibHac/Fs/LocalFile.cs rename to src/LibHac/FsSystem/LocalFile.cs index 4cb9e655..4d7abd4b 100644 --- a/src/LibHac/Fs/LocalFile.cs +++ b/src/LibHac/FsSystem/LocalFile.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class LocalFile : FileBase { diff --git a/src/LibHac/Fs/LocalFileSystem.cs b/src/LibHac/FsSystem/LocalFileSystem.cs similarity index 99% rename from src/LibHac/Fs/LocalFileSystem.cs rename to src/LibHac/FsSystem/LocalFileSystem.cs index 33c4b28b..dea5ba32 100644 --- a/src/LibHac/Fs/LocalFileSystem.cs +++ b/src/LibHac/FsSystem/LocalFileSystem.cs @@ -2,7 +2,7 @@ using System.IO; using System.Security; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class LocalFileSystem : IAttributeFileSystem { diff --git a/src/LibHac/Fs/LocalStorage.cs b/src/LibHac/FsSystem/LocalStorage.cs similarity index 97% rename from src/LibHac/Fs/LocalStorage.cs rename to src/LibHac/FsSystem/LocalStorage.cs index ea5b6e20..7e8d6596 100644 --- a/src/LibHac/Fs/LocalStorage.cs +++ b/src/LibHac/FsSystem/LocalStorage.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class LocalStorage : StorageBase { diff --git a/src/LibHac/Fs/MemoryStorage.cs b/src/LibHac/FsSystem/MemoryStorage.cs similarity index 99% rename from src/LibHac/Fs/MemoryStorage.cs rename to src/LibHac/FsSystem/MemoryStorage.cs index 23c025ff..9b139158 100644 --- a/src/LibHac/Fs/MemoryStorage.cs +++ b/src/LibHac/FsSystem/MemoryStorage.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class MemoryStorage : StorageBase { diff --git a/src/LibHac/Fs/Messages.cs b/src/LibHac/FsSystem/Messages.cs similarity index 95% rename from src/LibHac/Fs/Messages.cs rename to src/LibHac/FsSystem/Messages.cs index c9835942..63b58cae 100644 --- a/src/LibHac/Fs/Messages.cs +++ b/src/LibHac/FsSystem/Messages.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs +namespace LibHac.FsSystem { internal static class Messages { diff --git a/src/LibHac/Fs/NcaUtils/Nca.cs b/src/LibHac/FsSystem/NcaUtils/Nca.cs similarity index 99% rename from src/LibHac/Fs/NcaUtils/Nca.cs rename to src/LibHac/FsSystem/NcaUtils/Nca.cs index ed892d26..9cb388e6 100644 --- a/src/LibHac/Fs/NcaUtils/Nca.cs +++ b/src/LibHac/FsSystem/NcaUtils/Nca.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using LibHac.Fs.RomFs; +using LibHac.FsSystem.RomFs; -namespace LibHac.Fs.NcaUtils +namespace LibHac.FsSystem.NcaUtils { public class Nca { diff --git a/src/LibHac/Fs/NcaUtils/NcaExtensions.cs b/src/LibHac/FsSystem/NcaUtils/NcaExtensions.cs similarity index 99% rename from src/LibHac/Fs/NcaUtils/NcaExtensions.cs rename to src/LibHac/FsSystem/NcaUtils/NcaExtensions.cs index 72cbc384..5138a917 100644 --- a/src/LibHac/Fs/NcaUtils/NcaExtensions.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaExtensions.cs @@ -2,7 +2,7 @@ using System.Buffers.Binary; using System.Diagnostics; -namespace LibHac.Fs.NcaUtils +namespace LibHac.FsSystem.NcaUtils { public static class NcaExtensions { diff --git a/src/LibHac/Fs/NcaUtils/NcaFsHeader.cs b/src/LibHac/FsSystem/NcaUtils/NcaFsHeader.cs similarity index 98% rename from src/LibHac/Fs/NcaUtils/NcaFsHeader.cs rename to src/LibHac/FsSystem/NcaUtils/NcaFsHeader.cs index e9dd9f52..a09bb783 100644 --- a/src/LibHac/Fs/NcaUtils/NcaFsHeader.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaFsHeader.cs @@ -4,7 +4,7 @@ using System.Runtime.InteropServices; // ReSharper disable ImpureMethodCallOnReadonlyValueField -namespace LibHac.Fs.NcaUtils +namespace LibHac.FsSystem.NcaUtils { public struct NcaFsHeader { diff --git a/src/LibHac/Fs/NcaUtils/NcaFsIntegrityInfoIvfc.cs b/src/LibHac/FsSystem/NcaUtils/NcaFsIntegrityInfoIvfc.cs similarity index 98% rename from src/LibHac/Fs/NcaUtils/NcaFsIntegrityInfoIvfc.cs rename to src/LibHac/FsSystem/NcaUtils/NcaFsIntegrityInfoIvfc.cs index 5f42be72..5e290c86 100644 --- a/src/LibHac/Fs/NcaUtils/NcaFsIntegrityInfoIvfc.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaFsIntegrityInfoIvfc.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace LibHac.Fs.NcaUtils +namespace LibHac.FsSystem.NcaUtils { public struct NcaFsIntegrityInfoIvfc { diff --git a/src/LibHac/Fs/NcaUtils/NcaFsIntegrityInfoSha256.cs b/src/LibHac/FsSystem/NcaUtils/NcaFsIntegrityInfoSha256.cs similarity index 98% rename from src/LibHac/Fs/NcaUtils/NcaFsIntegrityInfoSha256.cs rename to src/LibHac/FsSystem/NcaUtils/NcaFsIntegrityInfoSha256.cs index 785f339d..7a8abd4d 100644 --- a/src/LibHac/Fs/NcaUtils/NcaFsIntegrityInfoSha256.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaFsIntegrityInfoSha256.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace LibHac.Fs.NcaUtils +namespace LibHac.FsSystem.NcaUtils { public struct NcaFsIntegrityInfoSha256 { diff --git a/src/LibHac/Fs/NcaUtils/NcaFsPatchInfo.cs b/src/LibHac/FsSystem/NcaUtils/NcaFsPatchInfo.cs similarity index 97% rename from src/LibHac/Fs/NcaUtils/NcaFsPatchInfo.cs rename to src/LibHac/FsSystem/NcaUtils/NcaFsPatchInfo.cs index 5e75fba4..ccbbdff3 100644 --- a/src/LibHac/Fs/NcaUtils/NcaFsPatchInfo.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaFsPatchInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace LibHac.Fs.NcaUtils +namespace LibHac.FsSystem.NcaUtils { public struct NcaFsPatchInfo { diff --git a/src/LibHac/Fs/NcaUtils/NcaHeader.cs b/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs similarity index 99% rename from src/LibHac/Fs/NcaUtils/NcaHeader.cs rename to src/LibHac/FsSystem/NcaUtils/NcaHeader.cs index d4580f9a..6f19818b 100644 --- a/src/LibHac/Fs/NcaUtils/NcaHeader.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs @@ -3,7 +3,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace LibHac.Fs.NcaUtils +namespace LibHac.FsSystem.NcaUtils { public struct NcaHeader { diff --git a/src/LibHac/Fs/NcaUtils/NcaKeyType.cs b/src/LibHac/FsSystem/NcaUtils/NcaKeyType.cs similarity index 76% rename from src/LibHac/Fs/NcaUtils/NcaKeyType.cs rename to src/LibHac/FsSystem/NcaUtils/NcaKeyType.cs index ac9d419e..589732e4 100644 --- a/src/LibHac/Fs/NcaUtils/NcaKeyType.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaKeyType.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs.NcaUtils +namespace LibHac.FsSystem.NcaUtils { internal enum NcaKeyType { diff --git a/src/LibHac/Fs/NcaUtils/NcaStructs.cs b/src/LibHac/FsSystem/NcaUtils/NcaStructs.cs similarity index 97% rename from src/LibHac/Fs/NcaUtils/NcaStructs.cs rename to src/LibHac/FsSystem/NcaUtils/NcaStructs.cs index f8fdc052..fe4a2977 100644 --- a/src/LibHac/Fs/NcaUtils/NcaStructs.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaStructs.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs.NcaUtils +namespace LibHac.FsSystem.NcaUtils { public class TitleVersion { diff --git a/src/LibHac/Fs/NullFile.cs b/src/LibHac/FsSystem/NullFile.cs similarity index 97% rename from src/LibHac/Fs/NullFile.cs rename to src/LibHac/FsSystem/NullFile.cs index 8c396639..44847aa3 100644 --- a/src/LibHac/Fs/NullFile.cs +++ b/src/LibHac/FsSystem/NullFile.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class NullFile : FileBase { diff --git a/src/LibHac/Fs/NullStorage.cs b/src/LibHac/FsSystem/NullStorage.cs similarity index 97% rename from src/LibHac/Fs/NullStorage.cs rename to src/LibHac/FsSystem/NullStorage.cs index 5643e70b..a019e898 100644 --- a/src/LibHac/Fs/NullStorage.cs +++ b/src/LibHac/FsSystem/NullStorage.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { /// /// An that returns all zeros when read, and does nothing on write. diff --git a/src/LibHac/Fs/NxFileStream.cs b/src/LibHac/FsSystem/NxFileStream.cs similarity index 98% rename from src/LibHac/Fs/NxFileStream.cs rename to src/LibHac/FsSystem/NxFileStream.cs index fd2a0852..7d6dd02b 100644 --- a/src/LibHac/Fs/NxFileStream.cs +++ b/src/LibHac/FsSystem/NxFileStream.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class NxFileStream : Stream { diff --git a/src/LibHac/Fs/PartitionDirectory.cs b/src/LibHac/FsSystem/PartitionDirectory.cs similarity index 98% rename from src/LibHac/Fs/PartitionDirectory.cs rename to src/LibHac/FsSystem/PartitionDirectory.cs index 4f8feaba..518c1350 100644 --- a/src/LibHac/Fs/PartitionDirectory.cs +++ b/src/LibHac/FsSystem/PartitionDirectory.cs @@ -3,7 +3,7 @@ using System.IO; using System.Text; using LibHac.Common; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class PartitionDirectory : IDirectory { diff --git a/src/LibHac/Fs/PartitionFile.cs b/src/LibHac/FsSystem/PartitionFile.cs similarity index 98% rename from src/LibHac/Fs/PartitionFile.cs rename to src/LibHac/FsSystem/PartitionFile.cs index 1802ea87..62a6c213 100644 --- a/src/LibHac/Fs/PartitionFile.cs +++ b/src/LibHac/FsSystem/PartitionFile.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class PartitionFile : FileBase { diff --git a/src/LibHac/Fs/PartitionFileSystem.cs b/src/LibHac/FsSystem/PartitionFileSystem.cs similarity index 99% rename from src/LibHac/Fs/PartitionFileSystem.cs rename to src/LibHac/FsSystem/PartitionFileSystem.cs index a8ba92d4..4012cfba 100644 --- a/src/LibHac/Fs/PartitionFileSystem.cs +++ b/src/LibHac/FsSystem/PartitionFileSystem.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Text; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class PartitionFileSystem : IFileSystem { diff --git a/src/LibHac/Fs/PartitionFileSystemBuilder.cs b/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs similarity index 99% rename from src/LibHac/Fs/PartitionFileSystemBuilder.cs rename to src/LibHac/FsSystem/PartitionFileSystemBuilder.cs index 853ae77a..bbe4a0b4 100644 --- a/src/LibHac/Fs/PartitionFileSystemBuilder.cs +++ b/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Security.Cryptography; using System.Text; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class PartitionFileSystemBuilder { diff --git a/src/LibHac/Fs/PathParser.cs b/src/LibHac/FsSystem/PathParser.cs similarity index 99% rename from src/LibHac/Fs/PathParser.cs rename to src/LibHac/FsSystem/PathParser.cs index afe148cf..e6c3f51e 100644 --- a/src/LibHac/Fs/PathParser.cs +++ b/src/LibHac/FsSystem/PathParser.cs @@ -1,7 +1,7 @@ using System; using System.Diagnostics; -namespace LibHac.Fs +namespace LibHac.FsSystem { /// /// Enumerates a file or directory path one segment at a time. diff --git a/src/LibHac/Fs/PathTools.cs b/src/LibHac/FsSystem/PathTools.cs similarity index 99% rename from src/LibHac/Fs/PathTools.cs rename to src/LibHac/FsSystem/PathTools.cs index d5ad17f8..bb7cf41a 100644 --- a/src/LibHac/Fs/PathTools.cs +++ b/src/LibHac/FsSystem/PathTools.cs @@ -6,7 +6,7 @@ using System.Runtime.CompilerServices; using System.IO.Enumeration; #endif -namespace LibHac.Fs +namespace LibHac.FsSystem { public static class PathTools { diff --git a/src/LibHac/Fs/ReadOnlyFile.cs b/src/LibHac/FsSystem/ReadOnlyFile.cs similarity index 97% rename from src/LibHac/Fs/ReadOnlyFile.cs rename to src/LibHac/FsSystem/ReadOnlyFile.cs index f98b8b24..c93be5ba 100644 --- a/src/LibHac/Fs/ReadOnlyFile.cs +++ b/src/LibHac/FsSystem/ReadOnlyFile.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class ReadOnlyFile : FileBase { diff --git a/src/LibHac/Fs/ReadOnlyFileSystem.cs b/src/LibHac/FsSystem/ReadOnlyFileSystem.cs similarity index 99% rename from src/LibHac/Fs/ReadOnlyFileSystem.cs rename to src/LibHac/FsSystem/ReadOnlyFileSystem.cs index a4fc43d7..a3c35b94 100644 --- a/src/LibHac/Fs/ReadOnlyFileSystem.cs +++ b/src/LibHac/FsSystem/ReadOnlyFileSystem.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class ReadOnlyFileSystem : IFileSystem { diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/FsSystem/ResultFs.cs similarity index 99% rename from src/LibHac/Fs/ResultFs.cs rename to src/LibHac/FsSystem/ResultFs.cs index fcc8eb68..0f064a80 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/FsSystem/ResultFs.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs +namespace LibHac.FsSystem { public class ResultFs { diff --git a/src/LibHac/Fs/ResultRangeFs.cs b/src/LibHac/FsSystem/ResultRangeFs.cs similarity index 97% rename from src/LibHac/Fs/ResultRangeFs.cs rename to src/LibHac/FsSystem/ResultRangeFs.cs index f0289aeb..3ffd032d 100644 --- a/src/LibHac/Fs/ResultRangeFs.cs +++ b/src/LibHac/FsSystem/ResultRangeFs.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs +namespace LibHac.FsSystem { public static class ResultRangeFs { diff --git a/src/LibHac/Fs/RightsId.cs b/src/LibHac/FsSystem/RightsId.cs similarity index 98% rename from src/LibHac/Fs/RightsId.cs rename to src/LibHac/FsSystem/RightsId.cs index 11f0969d..d3ac5836 100644 --- a/src/LibHac/Fs/RightsId.cs +++ b/src/LibHac/FsSystem/RightsId.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using LibHac.Common; -namespace LibHac.Fs +namespace LibHac.FsSystem { [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct RightsId : IEquatable, IComparable, IComparable diff --git a/src/LibHac/Fs/RomFs/HierarchicalRomFileTable.cs b/src/LibHac/FsSystem/RomFs/HierarchicalRomFileTable.cs similarity index 99% rename from src/LibHac/Fs/RomFs/HierarchicalRomFileTable.cs rename to src/LibHac/FsSystem/RomFs/HierarchicalRomFileTable.cs index b73b2efd..c6476ec5 100644 --- a/src/LibHac/Fs/RomFs/HierarchicalRomFileTable.cs +++ b/src/LibHac/FsSystem/RomFs/HierarchicalRomFileTable.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace LibHac.Fs.RomFs +namespace LibHac.FsSystem.RomFs { /// /// Represents the file table used by the RomFS format. diff --git a/src/LibHac/Fs/RomFs/RomFsBuilder.cs b/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs similarity index 99% rename from src/LibHac/Fs/RomFs/RomFsBuilder.cs rename to src/LibHac/FsSystem/RomFs/RomFsBuilder.cs index c4ab96d8..3ec7cbb8 100644 --- a/src/LibHac/Fs/RomFs/RomFsBuilder.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -namespace LibHac.Fs.RomFs +namespace LibHac.FsSystem.RomFs { /// /// Builds a RomFS from a collection of files. diff --git a/src/LibHac/Fs/RomFs/RomFsDictionary.cs b/src/LibHac/FsSystem/RomFs/RomFsDictionary.cs similarity index 99% rename from src/LibHac/Fs/RomFs/RomFsDictionary.cs rename to src/LibHac/FsSystem/RomFs/RomFsDictionary.cs index b1a5142f..d93970c9 100644 --- a/src/LibHac/Fs/RomFs/RomFsDictionary.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsDictionary.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace LibHac.Fs.RomFs +namespace LibHac.FsSystem.RomFs { // todo: Change constraint to "unmanaged" after updating to // a newer SDK https://github.com/dotnet/csharplang/issues/1937 diff --git a/src/LibHac/Fs/RomFs/RomFsDirectory.cs b/src/LibHac/FsSystem/RomFs/RomFsDirectory.cs similarity index 98% rename from src/LibHac/Fs/RomFs/RomFsDirectory.cs rename to src/LibHac/FsSystem/RomFs/RomFsDirectory.cs index 7b39248c..3d0ae58a 100644 --- a/src/LibHac/Fs/RomFs/RomFsDirectory.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsDirectory.cs @@ -2,7 +2,7 @@ using System.Text; using LibHac.Common; -namespace LibHac.Fs.RomFs +namespace LibHac.FsSystem.RomFs { public class RomFsDirectory : IDirectory { diff --git a/src/LibHac/Fs/RomFs/RomFsEntries.cs b/src/LibHac/FsSystem/RomFs/RomFsEntries.cs similarity index 97% rename from src/LibHac/Fs/RomFs/RomFsEntries.cs rename to src/LibHac/FsSystem/RomFs/RomFsEntries.cs index 5c12b8cd..8e6a4e7e 100644 --- a/src/LibHac/Fs/RomFs/RomFsEntries.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsEntries.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace LibHac.Fs.RomFs +namespace LibHac.FsSystem.RomFs { internal ref struct RomEntryKey { diff --git a/src/LibHac/Fs/RomFs/RomFsFile.cs b/src/LibHac/FsSystem/RomFs/RomFsFile.cs similarity index 97% rename from src/LibHac/Fs/RomFs/RomFsFile.cs rename to src/LibHac/FsSystem/RomFs/RomFsFile.cs index 5f58a54a..42aa8493 100644 --- a/src/LibHac/Fs/RomFs/RomFsFile.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsFile.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs.RomFs +namespace LibHac.FsSystem.RomFs { public class RomFsFile : FileBase { diff --git a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs b/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs similarity index 99% rename from src/LibHac/Fs/RomFs/RomFsFileSystem.cs rename to src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs index 4651a177..b2b6f718 100644 --- a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs.RomFs +namespace LibHac.FsSystem.RomFs { public class RomFsFileSystem : IFileSystem { diff --git a/src/LibHac/Fs/Save/AllocationTable.cs b/src/LibHac/FsSystem/Save/AllocationTable.cs similarity index 99% rename from src/LibHac/Fs/Save/AllocationTable.cs rename to src/LibHac/FsSystem/Save/AllocationTable.cs index c43ec471..a09e9deb 100644 --- a/src/LibHac/Fs/Save/AllocationTable.cs +++ b/src/LibHac/FsSystem/Save/AllocationTable.cs @@ -3,7 +3,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class AllocationTable { diff --git a/src/LibHac/Fs/Save/AllocationTableIterator.cs b/src/LibHac/FsSystem/Save/AllocationTableIterator.cs similarity index 98% rename from src/LibHac/Fs/Save/AllocationTableIterator.cs rename to src/LibHac/FsSystem/Save/AllocationTableIterator.cs index e97b79e9..886eb5be 100644 --- a/src/LibHac/Fs/Save/AllocationTableIterator.cs +++ b/src/LibHac/FsSystem/Save/AllocationTableIterator.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class AllocationTableIterator { diff --git a/src/LibHac/Fs/Save/AllocationTableStorage.cs b/src/LibHac/FsSystem/Save/AllocationTableStorage.cs similarity index 99% rename from src/LibHac/Fs/Save/AllocationTableStorage.cs rename to src/LibHac/FsSystem/Save/AllocationTableStorage.cs index c15102b1..cf66ff44 100644 --- a/src/LibHac/Fs/Save/AllocationTableStorage.cs +++ b/src/LibHac/FsSystem/Save/AllocationTableStorage.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class AllocationTableStorage : StorageBase { diff --git a/src/LibHac/Fs/Save/DuplexBitmap.cs b/src/LibHac/FsSystem/Save/DuplexBitmap.cs similarity index 97% rename from src/LibHac/Fs/Save/DuplexBitmap.cs rename to src/LibHac/FsSystem/Save/DuplexBitmap.cs index 649ef785..e76d2492 100644 --- a/src/LibHac/Fs/Save/DuplexBitmap.cs +++ b/src/LibHac/FsSystem/Save/DuplexBitmap.cs @@ -2,7 +2,7 @@ using System.Collections; using System.IO; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class DuplexBitmap { diff --git a/src/LibHac/Fs/Save/DuplexStorage.cs b/src/LibHac/FsSystem/Save/DuplexStorage.cs similarity index 99% rename from src/LibHac/Fs/Save/DuplexStorage.cs rename to src/LibHac/FsSystem/Save/DuplexStorage.cs index 874af711..25206542 100644 --- a/src/LibHac/Fs/Save/DuplexStorage.cs +++ b/src/LibHac/FsSystem/Save/DuplexStorage.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class DuplexStorage : StorageBase { diff --git a/src/LibHac/Fs/Save/Header.cs b/src/LibHac/FsSystem/Save/Header.cs similarity index 99% rename from src/LibHac/Fs/Save/Header.cs rename to src/LibHac/FsSystem/Save/Header.cs index a0bc4ef8..7e8b908b 100644 --- a/src/LibHac/Fs/Save/Header.cs +++ b/src/LibHac/FsSystem/Save/Header.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class Header { diff --git a/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs b/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs similarity index 98% rename from src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs rename to src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs index 75c6ecc8..0c4c212a 100644 --- a/src/LibHac/Fs/Save/HierarchicalDuplexStorage.cs +++ b/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class HierarchicalDuplexStorage : StorageBase { diff --git a/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs b/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs similarity index 99% rename from src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs rename to src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs index 78555ee3..359bea1b 100644 --- a/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs +++ b/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs @@ -2,7 +2,7 @@ using System.IO; using System.Runtime.InteropServices; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class HierarchicalSaveFileTable { diff --git a/src/LibHac/Fs/Save/ISaveDataExtraDataAccessor.cs b/src/LibHac/FsSystem/Save/ISaveDataExtraDataAccessor.cs similarity index 83% rename from src/LibHac/Fs/Save/ISaveDataExtraDataAccessor.cs rename to src/LibHac/FsSystem/Save/ISaveDataExtraDataAccessor.cs index 6b93ffab..707e172a 100644 --- a/src/LibHac/Fs/Save/ISaveDataExtraDataAccessor.cs +++ b/src/LibHac/FsSystem/Save/ISaveDataExtraDataAccessor.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public interface ISaveDataExtraDataAccessor { diff --git a/src/LibHac/Fs/Save/JournalMap.cs b/src/LibHac/FsSystem/Save/JournalMap.cs similarity index 99% rename from src/LibHac/Fs/Save/JournalMap.cs rename to src/LibHac/FsSystem/Save/JournalMap.cs index d49af98c..c03dae94 100644 --- a/src/LibHac/Fs/Save/JournalMap.cs +++ b/src/LibHac/FsSystem/Save/JournalMap.cs @@ -1,6 +1,6 @@ using System.IO; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class JournalMap { diff --git a/src/LibHac/Fs/Save/JournalStorage.cs b/src/LibHac/FsSystem/Save/JournalStorage.cs similarity index 99% rename from src/LibHac/Fs/Save/JournalStorage.cs rename to src/LibHac/FsSystem/Save/JournalStorage.cs index ba4ac0bf..05f162d0 100644 --- a/src/LibHac/Fs/Save/JournalStorage.cs +++ b/src/LibHac/FsSystem/Save/JournalStorage.cs @@ -2,7 +2,7 @@ using System.Collections; using System.IO; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class JournalStorage : StorageBase { diff --git a/src/LibHac/Fs/Save/RemapStorage.cs b/src/LibHac/FsSystem/Save/RemapStorage.cs similarity index 99% rename from src/LibHac/Fs/Save/RemapStorage.cs rename to src/LibHac/FsSystem/Save/RemapStorage.cs index 885691f4..74fee6e4 100644 --- a/src/LibHac/Fs/Save/RemapStorage.cs +++ b/src/LibHac/FsSystem/Save/RemapStorage.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class RemapStorage : StorageBase { diff --git a/src/LibHac/Fs/Save/SaveDataDirectory.cs b/src/LibHac/FsSystem/Save/SaveDataDirectory.cs similarity index 98% rename from src/LibHac/Fs/Save/SaveDataDirectory.cs rename to src/LibHac/FsSystem/Save/SaveDataDirectory.cs index c4a73343..7062a58e 100644 --- a/src/LibHac/Fs/Save/SaveDataDirectory.cs +++ b/src/LibHac/FsSystem/Save/SaveDataDirectory.cs @@ -2,7 +2,7 @@ using System.Text; using LibHac.Common; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class SaveDataDirectory : IDirectory { diff --git a/src/LibHac/Fs/Save/SaveDataFile.cs b/src/LibHac/FsSystem/Save/SaveDataFile.cs similarity index 98% rename from src/LibHac/Fs/Save/SaveDataFile.cs rename to src/LibHac/FsSystem/Save/SaveDataFile.cs index 784350d9..8dc2f3d8 100644 --- a/src/LibHac/Fs/Save/SaveDataFile.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFile.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class SaveDataFile : FileBase { diff --git a/src/LibHac/Fs/Save/SaveDataFileSystem.cs b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs similarity index 99% rename from src/LibHac/Fs/Save/SaveDataFileSystem.cs rename to src/LibHac/FsSystem/Save/SaveDataFileSystem.cs index e71d1a0c..b2874841 100644 --- a/src/LibHac/Fs/Save/SaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class SaveDataFileSystem : IFileSystem { diff --git a/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs b/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs similarity index 99% rename from src/LibHac/Fs/Save/SaveDataFileSystemCore.cs rename to src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs index c408a325..c0929ec3 100644 --- a/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public class SaveDataFileSystemCore : IFileSystem { diff --git a/src/LibHac/Fs/Save/SaveExtensions.cs b/src/LibHac/FsSystem/Save/SaveExtensions.cs similarity index 93% rename from src/LibHac/Fs/Save/SaveExtensions.cs rename to src/LibHac/FsSystem/Save/SaveExtensions.cs index 6c1ed069..0507f229 100644 --- a/src/LibHac/Fs/Save/SaveExtensions.cs +++ b/src/LibHac/FsSystem/Save/SaveExtensions.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { public static class SaveExtensions { diff --git a/src/LibHac/Fs/Save/SaveFsEntry.cs b/src/LibHac/FsSystem/Save/SaveFsEntry.cs similarity index 96% rename from src/LibHac/Fs/Save/SaveFsEntry.cs rename to src/LibHac/FsSystem/Save/SaveFsEntry.cs index 1a4c14a7..49e01214 100644 --- a/src/LibHac/Fs/Save/SaveFsEntry.cs +++ b/src/LibHac/FsSystem/Save/SaveFsEntry.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { internal ref struct SaveEntryKey { diff --git a/src/LibHac/Fs/Save/SaveFsList.cs b/src/LibHac/FsSystem/Save/SaveFsList.cs similarity index 99% rename from src/LibHac/Fs/Save/SaveFsList.cs rename to src/LibHac/FsSystem/Save/SaveFsList.cs index 7870b119..47806a1a 100644 --- a/src/LibHac/Fs/Save/SaveFsList.cs +++ b/src/LibHac/FsSystem/Save/SaveFsList.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { // todo: Change constraint to "unmanaged" after updating to // a newer SDK https://github.com/dotnet/csharplang/issues/1937 diff --git a/src/LibHac/Fs/Save/SaveResults.cs b/src/LibHac/FsSystem/Save/SaveResults.cs similarity index 99% rename from src/LibHac/Fs/Save/SaveResults.cs rename to src/LibHac/FsSystem/Save/SaveResults.cs index 3935db9e..0ec59399 100644 --- a/src/LibHac/Fs/Save/SaveResults.cs +++ b/src/LibHac/FsSystem/Save/SaveResults.cs @@ -1,4 +1,4 @@ -namespace LibHac.Fs.Save +namespace LibHac.FsSystem.Save { internal static class SaveResults { diff --git a/src/LibHac/Fs/SaveDataAttribute.cs b/src/LibHac/FsSystem/SaveDataAttribute.cs similarity index 98% rename from src/LibHac/Fs/SaveDataAttribute.cs rename to src/LibHac/FsSystem/SaveDataAttribute.cs index d37c7ed3..d501602a 100644 --- a/src/LibHac/Fs/SaveDataAttribute.cs +++ b/src/LibHac/FsSystem/SaveDataAttribute.cs @@ -1,9 +1,9 @@ using System; using System.Buffers.Binary; -using LibHac.Fs.Save; +using LibHac.FsSystem.Save; using LibHac.Kvdb; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class SaveDataAttribute : IComparable, IComparable, IEquatable, IExportable { diff --git a/src/LibHac/Fs/SaveDataCreateInfo.cs b/src/LibHac/FsSystem/SaveDataCreateInfo.cs similarity index 86% rename from src/LibHac/Fs/SaveDataCreateInfo.cs rename to src/LibHac/FsSystem/SaveDataCreateInfo.cs index 9dee82af..875bb0e2 100644 --- a/src/LibHac/Fs/SaveDataCreateInfo.cs +++ b/src/LibHac/FsSystem/SaveDataCreateInfo.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace LibHac.Fs +namespace LibHac.FsSystem { [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct SaveDataCreateInfo diff --git a/src/LibHac/Fs/SaveDataStructs.cs b/src/LibHac/FsSystem/SaveDataStructs.cs similarity index 97% rename from src/LibHac/Fs/SaveDataStructs.cs rename to src/LibHac/FsSystem/SaveDataStructs.cs index b4435b97..ee2a2d7c 100644 --- a/src/LibHac/Fs/SaveDataStructs.cs +++ b/src/LibHac/FsSystem/SaveDataStructs.cs @@ -1,10 +1,10 @@ using System; using System.Runtime.InteropServices; using LibHac.Common; -using LibHac.Fs.Save; +using LibHac.FsSystem.Save; using LibHac.Ncm; -namespace LibHac.Fs +namespace LibHac.FsSystem { [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct SaveDataAttribute2 diff --git a/src/LibHac/Fs/SaveIndexerStruct.cs b/src/LibHac/FsSystem/SaveIndexerStruct.cs similarity index 98% rename from src/LibHac/Fs/SaveIndexerStruct.cs rename to src/LibHac/FsSystem/SaveIndexerStruct.cs index fedada8f..b51dfa6f 100644 --- a/src/LibHac/Fs/SaveIndexerStruct.cs +++ b/src/LibHac/FsSystem/SaveIndexerStruct.cs @@ -2,7 +2,7 @@ using System.Buffers.Binary; using LibHac.Kvdb; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class SaveIndexerStruct : IExportable { diff --git a/src/LibHac/Fs/SaveMetaCreateInfo.cs b/src/LibHac/FsSystem/SaveMetaCreateInfo.cs similarity index 90% rename from src/LibHac/Fs/SaveMetaCreateInfo.cs rename to src/LibHac/FsSystem/SaveMetaCreateInfo.cs index c22202db..a8677328 100644 --- a/src/LibHac/Fs/SaveMetaCreateInfo.cs +++ b/src/LibHac/FsSystem/SaveMetaCreateInfo.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace LibHac.Fs +namespace LibHac.FsSystem { [StructLayout(LayoutKind.Explicit, Size = 0x10)] public struct SaveMetaCreateInfo diff --git a/src/LibHac/Fs/SectorStorage.cs b/src/LibHac/FsSystem/SectorStorage.cs similarity index 98% rename from src/LibHac/Fs/SectorStorage.cs rename to src/LibHac/FsSystem/SectorStorage.cs index 16ef4898..6246ed9f 100644 --- a/src/LibHac/Fs/SectorStorage.cs +++ b/src/LibHac/FsSystem/SectorStorage.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class SectorStorage : StorageBase { diff --git a/src/LibHac/Fs/StorageBase.cs b/src/LibHac/FsSystem/StorageBase.cs similarity index 98% rename from src/LibHac/Fs/StorageBase.cs rename to src/LibHac/FsSystem/StorageBase.cs index 580479b7..0fada5e8 100644 --- a/src/LibHac/Fs/StorageBase.cs +++ b/src/LibHac/FsSystem/StorageBase.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace LibHac.Fs +namespace LibHac.FsSystem { public abstract class StorageBase : IStorage { diff --git a/src/LibHac/Fs/StorageExtensions.cs b/src/LibHac/FsSystem/StorageExtensions.cs similarity index 99% rename from src/LibHac/Fs/StorageExtensions.cs rename to src/LibHac/FsSystem/StorageExtensions.cs index a1f64dc7..46ee10e3 100644 --- a/src/LibHac/Fs/StorageExtensions.cs +++ b/src/LibHac/FsSystem/StorageExtensions.cs @@ -3,7 +3,7 @@ using System.Buffers; using System.IO; using System.Runtime.InteropServices; -namespace LibHac.Fs +namespace LibHac.FsSystem { public static class StorageExtensions { diff --git a/src/LibHac/Fs/StorageFile.cs b/src/LibHac/FsSystem/StorageFile.cs similarity index 98% rename from src/LibHac/Fs/StorageFile.cs rename to src/LibHac/FsSystem/StorageFile.cs index 176abdc5..32009c5f 100644 --- a/src/LibHac/Fs/StorageFile.cs +++ b/src/LibHac/FsSystem/StorageFile.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class StorageFile : FileBase { diff --git a/src/LibHac/Fs/StorageStream.cs b/src/LibHac/FsSystem/StorageStream.cs similarity index 98% rename from src/LibHac/Fs/StorageStream.cs rename to src/LibHac/FsSystem/StorageStream.cs index 85cbef72..265e1edf 100644 --- a/src/LibHac/Fs/StorageStream.cs +++ b/src/LibHac/FsSystem/StorageStream.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class StorageStream : Stream { diff --git a/src/LibHac/Fs/StreamFile.cs b/src/LibHac/FsSystem/StreamFile.cs similarity index 99% rename from src/LibHac/Fs/StreamFile.cs rename to src/LibHac/FsSystem/StreamFile.cs index ba7305db..2103166c 100644 --- a/src/LibHac/Fs/StreamFile.cs +++ b/src/LibHac/FsSystem/StreamFile.cs @@ -5,7 +5,7 @@ using System.IO; using System.Buffers; #endif -namespace LibHac.Fs +namespace LibHac.FsSystem { /// /// Provides an interface for interacting with a diff --git a/src/LibHac/Fs/StreamStorage.cs b/src/LibHac/FsSystem/StreamStorage.cs similarity index 99% rename from src/LibHac/Fs/StreamStorage.cs rename to src/LibHac/FsSystem/StreamStorage.cs index 4784da48..7381f63a 100644 --- a/src/LibHac/Fs/StreamStorage.cs +++ b/src/LibHac/FsSystem/StreamStorage.cs @@ -5,7 +5,7 @@ using System.IO; using System.Buffers; #endif -namespace LibHac.Fs +namespace LibHac.FsSystem { public class StreamStorage : StorageBase { diff --git a/src/LibHac/Fs/SubStorage.cs b/src/LibHac/FsSystem/SubStorage.cs similarity index 99% rename from src/LibHac/Fs/SubStorage.cs rename to src/LibHac/FsSystem/SubStorage.cs index 144b7ab0..82616040 100644 --- a/src/LibHac/Fs/SubStorage.cs +++ b/src/LibHac/FsSystem/SubStorage.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class SubStorage : StorageBase { diff --git a/src/LibHac/Fs/SubdirectoryFileSystem.cs b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs similarity index 99% rename from src/LibHac/Fs/SubdirectoryFileSystem.cs rename to src/LibHac/FsSystem/SubdirectoryFileSystem.cs index b5fabd41..9c2df12f 100644 --- a/src/LibHac/Fs/SubdirectoryFileSystem.cs +++ b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.Fs +namespace LibHac.FsSystem { public class SubdirectoryFileSystem : IFileSystem { diff --git a/src/LibHac/Fs/UserId.cs b/src/LibHac/FsSystem/UserId.cs similarity index 98% rename from src/LibHac/Fs/UserId.cs rename to src/LibHac/FsSystem/UserId.cs index 4a14fc46..7332102a 100644 --- a/src/LibHac/Fs/UserId.cs +++ b/src/LibHac/FsSystem/UserId.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using LibHac.Common; -namespace LibHac.Fs +namespace LibHac.FsSystem { [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct UserId : IEquatable, IComparable, IComparable diff --git a/src/LibHac/Fs/ValueStringBuilder.cs b/src/LibHac/FsSystem/ValueStringBuilder.cs similarity index 99% rename from src/LibHac/Fs/ValueStringBuilder.cs rename to src/LibHac/FsSystem/ValueStringBuilder.cs index 93a1f7da..4765aa4b 100644 --- a/src/LibHac/Fs/ValueStringBuilder.cs +++ b/src/LibHac/FsSystem/ValueStringBuilder.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace LibHac.Fs +namespace LibHac.FsSystem { internal ref struct ValueStringBuilder { diff --git a/src/LibHac/Horizon.cs b/src/LibHac/Horizon.cs index 370dc5b2..cd9da365 100644 --- a/src/LibHac/Horizon.cs +++ b/src/LibHac/Horizon.cs @@ -1,4 +1,4 @@ -using LibHac.FsClient; +using LibHac.Fs; using LibHac.FsService; using LibHac.FsService.Creators; diff --git a/src/LibHac/Keyset.cs b/src/LibHac/Keyset.cs index d48e625e..e71deaa8 100644 --- a/src/LibHac/Keyset.cs +++ b/src/LibHac/Keyset.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac { diff --git a/src/LibHac/Kip.cs b/src/LibHac/Kip.cs index f007713d..ac0e6b20 100644 --- a/src/LibHac/Kip.cs +++ b/src/LibHac/Kip.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac { diff --git a/src/LibHac/Ncm/IContentStorage.cs b/src/LibHac/Ncm/IContentStorage.cs index 2cd17ea9..9834f3a0 100644 --- a/src/LibHac/Ncm/IContentStorage.cs +++ b/src/LibHac/Ncm/IContentStorage.cs @@ -1,5 +1,5 @@ using System; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.Ncm { diff --git a/src/LibHac/Nro.cs b/src/LibHac/Nro.cs index c3e301db..1afd9710 100644 --- a/src/LibHac/Nro.cs +++ b/src/LibHac/Nro.cs @@ -1,5 +1,5 @@ using System.IO; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac { diff --git a/src/LibHac/Nso.cs b/src/LibHac/Nso.cs index 53c35063..09e49b96 100644 --- a/src/LibHac/Nso.cs +++ b/src/LibHac/Nso.cs @@ -1,6 +1,6 @@ using System.Collections; using System.IO; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac { diff --git a/src/LibHac/Package1.cs b/src/LibHac/Package1.cs index 0c4efc20..b94f7f8e 100644 --- a/src/LibHac/Package1.cs +++ b/src/LibHac/Package1.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac { diff --git a/src/LibHac/Package2.cs b/src/LibHac/Package2.cs index 943dab71..dee1e26c 100644 --- a/src/LibHac/Package2.cs +++ b/src/LibHac/Package2.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac { diff --git a/src/LibHac/SwitchFs.cs b/src/LibHac/SwitchFs.cs index f87b879a..d6455293 100644 --- a/src/LibHac/SwitchFs.cs +++ b/src/LibHac/SwitchFs.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using LibHac.Fs; -using LibHac.Fs.NcaUtils; -using LibHac.Fs.Save; +using LibHac.FsSystem; +using LibHac.FsSystem.NcaUtils; +using LibHac.FsSystem.Save; using LibHac.Ncm; namespace LibHac diff --git a/src/LibHac/Xci.cs b/src/LibHac/Xci.cs index 9fe8c7f1..4154f43f 100644 --- a/src/LibHac/Xci.cs +++ b/src/LibHac/Xci.cs @@ -1,4 +1,4 @@ -using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac { diff --git a/src/hactoolnet/AccessLog.cs b/src/hactoolnet/AccessLog.cs index 617e7eaf..789965c6 100644 --- a/src/hactoolnet/AccessLog.cs +++ b/src/hactoolnet/AccessLog.cs @@ -2,7 +2,7 @@ using System.IO; using System.Runtime.CompilerServices; using LibHac; -using LibHac.FsClient; +using LibHac.Fs; namespace hactoolnet { diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index 9aa361ee..05cfaa33 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -2,7 +2,7 @@ using System.Buffers; using LibHac; using LibHac.Fs; -using LibHac.FsClient; +using LibHac.FsSystem; namespace hactoolnet { diff --git a/src/hactoolnet/Options.cs b/src/hactoolnet/Options.cs index 1a327eaf..c99ac0a8 100644 --- a/src/hactoolnet/Options.cs +++ b/src/hactoolnet/Options.cs @@ -1,5 +1,5 @@ using LibHac; -using LibHac.Fs; +using LibHac.FsSystem; namespace hactoolnet { diff --git a/src/hactoolnet/Print.cs b/src/hactoolnet/Print.cs index 0cea2972..ab5b6348 100644 --- a/src/hactoolnet/Print.cs +++ b/src/hactoolnet/Print.cs @@ -2,8 +2,8 @@ using System.Buffers.Binary; using System.Text; using LibHac; -using LibHac.Fs; -using LibHac.Fs.NcaUtils; +using LibHac.FsSystem; +using LibHac.FsSystem.NcaUtils; namespace hactoolnet { diff --git a/src/hactoolnet/ProcessBench.cs b/src/hactoolnet/ProcessBench.cs index 185006a4..1f889940 100644 --- a/src/hactoolnet/ProcessBench.cs +++ b/src/hactoolnet/ProcessBench.cs @@ -1,6 +1,6 @@ using System.Diagnostics; using LibHac; -using LibHac.Fs; +using LibHac.FsSystem; namespace hactoolnet { diff --git a/src/hactoolnet/ProcessDelta.cs b/src/hactoolnet/ProcessDelta.cs index b03dde02..3ab22e4b 100644 --- a/src/hactoolnet/ProcessDelta.cs +++ b/src/hactoolnet/ProcessDelta.cs @@ -2,8 +2,8 @@ using System.IO; using System.Runtime.InteropServices; using System.Text; -using LibHac.Fs; -using LibHac.Fs.NcaUtils; +using LibHac.FsSystem; +using LibHac.FsSystem.NcaUtils; using static hactoolnet.Print; namespace hactoolnet diff --git a/src/hactoolnet/ProcessFsBuild.cs b/src/hactoolnet/ProcessFsBuild.cs index 05a969f2..b9162cde 100644 --- a/src/hactoolnet/ProcessFsBuild.cs +++ b/src/hactoolnet/ProcessFsBuild.cs @@ -1,6 +1,6 @@ using System.IO; -using LibHac.Fs; -using LibHac.Fs.RomFs; +using LibHac.FsSystem; +using LibHac.FsSystem.RomFs; namespace hactoolnet { diff --git a/src/hactoolnet/ProcessKip.cs b/src/hactoolnet/ProcessKip.cs index b10e4d35..1cbfacbc 100644 --- a/src/hactoolnet/ProcessKip.cs +++ b/src/hactoolnet/ProcessKip.cs @@ -1,6 +1,6 @@ using System.IO; using LibHac; -using LibHac.Fs; +using LibHac.FsSystem; namespace hactoolnet { diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index 5cfc9e65..311b14a1 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -3,8 +3,8 @@ using System.Text; using LibHac; using LibHac.Common; using LibHac.Fs; -using LibHac.Fs.NcaUtils; -using LibHac.FsClient; +using LibHac.FsSystem; +using LibHac.FsSystem.NcaUtils; using LibHac.Npdm; using static hactoolnet.Print; diff --git a/src/hactoolnet/ProcessPackage.cs b/src/hactoolnet/ProcessPackage.cs index ee551196..7d2c043d 100644 --- a/src/hactoolnet/ProcessPackage.cs +++ b/src/hactoolnet/ProcessPackage.cs @@ -1,7 +1,7 @@ using System.IO; using System.Text; using LibHac; -using LibHac.Fs; +using LibHac.FsSystem; using static hactoolnet.Print; namespace hactoolnet diff --git a/src/hactoolnet/ProcessPfs.cs b/src/hactoolnet/ProcessPfs.cs index fbabfad7..c450f7ed 100644 --- a/src/hactoolnet/ProcessPfs.cs +++ b/src/hactoolnet/ProcessPfs.cs @@ -2,7 +2,7 @@ using System.Reflection; using System.Text; using LibHac; -using LibHac.Fs; +using LibHac.FsSystem; using static hactoolnet.Print; namespace hactoolnet diff --git a/src/hactoolnet/ProcessRomfs.cs b/src/hactoolnet/ProcessRomfs.cs index 950b757a..86af0c46 100644 --- a/src/hactoolnet/ProcessRomfs.cs +++ b/src/hactoolnet/ProcessRomfs.cs @@ -1,6 +1,6 @@ using System.IO; -using LibHac.Fs; -using LibHac.Fs.RomFs; +using LibHac.FsSystem; +using LibHac.FsSystem.RomFs; namespace hactoolnet { diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index 3bc937c3..4f067a7c 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -6,8 +6,8 @@ using System.Text; using LibHac; using LibHac.Common; using LibHac.Fs; -using LibHac.Fs.Save; -using LibHac.FsClient; +using LibHac.FsSystem; +using LibHac.FsSystem.Save; using static hactoolnet.Print; namespace hactoolnet diff --git a/src/hactoolnet/ProcessSwitchFs.cs b/src/hactoolnet/ProcessSwitchFs.cs index 9dfc8ba9..441346f8 100644 --- a/src/hactoolnet/ProcessSwitchFs.cs +++ b/src/hactoolnet/ProcessSwitchFs.cs @@ -4,9 +4,9 @@ using System.IO; using System.Linq; using System.Text; using LibHac; -using LibHac.Fs; -using LibHac.Fs.NcaUtils; -using LibHac.Fs.Save; +using LibHac.FsSystem; +using LibHac.FsSystem.NcaUtils; +using LibHac.FsSystem.Save; #if NETCOREAPP using System.Runtime.InteropServices; diff --git a/src/hactoolnet/ProcessXci.cs b/src/hactoolnet/ProcessXci.cs index 74d9996f..240830b4 100644 --- a/src/hactoolnet/ProcessXci.cs +++ b/src/hactoolnet/ProcessXci.cs @@ -3,8 +3,8 @@ using System.IO; using System.Linq; using System.Text; using LibHac; -using LibHac.Fs; -using LibHac.Fs.NcaUtils; +using LibHac.FsSystem; +using LibHac.FsSystem.NcaUtils; using static hactoolnet.Print; namespace hactoolnet diff --git a/tests/LibHac.Tests/AesXts.cs b/tests/LibHac.Tests/AesXts.cs index b2dd51dd..df7a9629 100644 --- a/tests/LibHac.Tests/AesXts.cs +++ b/tests/LibHac.Tests/AesXts.cs @@ -1,5 +1,5 @@ using System.Linq; -using LibHac.Fs; +using LibHac.FsSystem; using Xunit; namespace LibHac.Tests diff --git a/tests/LibHac.Tests/PathToolsTests.cs b/tests/LibHac.Tests/PathToolsTests.cs index fb3a04d9..ff4330fe 100644 --- a/tests/LibHac.Tests/PathToolsTests.cs +++ b/tests/LibHac.Tests/PathToolsTests.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using LibHac.Fs; +using LibHac.FsSystem; using Xunit; namespace LibHac.Tests diff --git a/tests/LibHac.Tests/RomFsTests.cs b/tests/LibHac.Tests/RomFsTests.cs index bce481ad..5163e8fa 100644 --- a/tests/LibHac.Tests/RomFsTests.cs +++ b/tests/LibHac.Tests/RomFsTests.cs @@ -1,5 +1,5 @@ using System; -using LibHac.Fs.RomFs; +using LibHac.FsSystem.RomFs; using Xunit; namespace LibHac.Tests From 0fe3031701886e7cbc474b183f0738d2dd49ce51 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 21 Sep 2019 13:05:45 -0500 Subject: [PATCH 23/46] Move common items to the Fs class --- src/LibHac/Common/Id128.cs | 2 +- src/LibHac/Fs/Accessors/MountTable.cs | 1 - src/LibHac/Fs/ContentStorage.cs | 1 - src/LibHac/{FsSystem => Fs}/DirectoryEntry.cs | 3 ++- src/LibHac/Fs/FileSystemClient.Directory.cs | 1 - src/LibHac/Fs/FileSystemClient.Mount.cs | 1 - src/LibHac/Fs/FileSystemClient.cs | 1 - src/LibHac/{FsSystem => Fs}/FileTimeStamp.cs | 2 +- src/LibHac/{FsSystem => Fs}/FsEnums.cs | 2 +- .../{FsSystem => Fs}/IAttributeFileSystem.cs | 2 +- src/LibHac/{FsSystem => Fs}/IDirectory.cs | 2 +- src/LibHac/{FsSystem => Fs}/IFile.cs | 3 ++- src/LibHac/{FsSystem => Fs}/IFileSystem.cs | 3 ++- src/LibHac/{FsSystem => Fs}/IStorage.cs | 2 +- src/LibHac/Fs/MountHelpers.cs | 2 +- src/LibHac/{FsSystem => Fs}/ResultFs.cs | 2 +- src/LibHac/{FsSystem => Fs}/ResultRangeFs.cs | 2 +- src/LibHac/{FsSystem => Fs}/RightsId.cs | 2 +- src/LibHac/{FsSystem => Fs}/SaveDataAttribute.cs | 2 +- src/LibHac/{FsSystem => Fs}/SaveDataStructs.cs | 15 ++++++++++++++- src/LibHac/{FsSystem => Fs}/UserId.cs | 2 +- .../Creators/EmulatedBisFileSystemCreator.cs | 2 +- .../EmulatedBisFileSystemCreatorConfig.cs | 2 +- .../Creators/EmulatedSdFileSystemCreator.cs | 2 +- .../Creators/EncryptedFileSystemCreator.cs | 1 + .../FsService/Creators/FileSystemCreators.cs | 2 +- .../FsService/Creators/IBuiltInStorageCreator.cs | 2 +- .../Creators/IBuiltInStorageFileSystemCreator.cs | 2 +- .../Creators/IEncryptedFileSystemCreator.cs | 2 +- .../FsService/Creators/IFatFileSystemCreator.cs | 2 +- .../Creators/IGameCardFileSystemCreator.cs | 2 +- .../FsService/Creators/IGameCardStorageCreator.cs | 2 +- .../FsService/Creators/IHostFileSystemCreator.cs | 2 +- .../FsService/Creators/IMemoryStorageCreator.cs | 2 +- .../Creators/IPartitionFileSystemCreator.cs | 2 +- .../FsService/Creators/IRomFileSystemCreator.cs | 2 +- .../Creators/ISaveDataFileSystemCreator.cs | 1 + .../FsService/Creators/ISdFileSystemCreator.cs | 2 +- .../FsService/Creators/ISdStorageCreator.cs | 2 +- .../FsService/Creators/IStorageOnNcaCreator.cs | 2 +- .../Creators/ISubDirectoryFileSystemCreator.cs | 2 +- .../Creators/ITargetManagerFileSystemCreator.cs | 2 +- .../Creators/SubDirectoryFileSystemCreator.cs | 3 ++- src/LibHac/FsService/FileSystemProxy.cs | 4 +++- src/LibHac/FsService/FileSystemProxyCore.cs | 6 +++--- src/LibHac/FsService/IFileSystemProxy.cs | 1 + .../{FsSystem => FsService}/SaveIndexerStruct.cs | 2 +- src/LibHac/FsService/Util.cs | 1 + src/LibHac/FsSystem/Aes128CtrExStorage.cs | 1 + src/LibHac/FsSystem/Aes128CtrStorage.cs | 1 + src/LibHac/FsSystem/Aes128XtsStorage.cs | 1 + src/LibHac/FsSystem/AesXtsDirectory.cs | 1 + src/LibHac/FsSystem/AesXtsFile.cs | 1 + src/LibHac/FsSystem/AesXtsFileHeader.cs | 1 + src/LibHac/FsSystem/AesXtsFileSystem.cs | 1 + src/LibHac/FsSystem/BucketTree.cs | 1 + src/LibHac/FsSystem/CachedStorage.cs | 1 + src/LibHac/FsSystem/ConcatenationDirectory.cs | 2 +- src/LibHac/FsSystem/ConcatenationFile.cs | 1 + src/LibHac/FsSystem/ConcatenationFileSystem.cs | 2 +- src/LibHac/FsSystem/ConcatenationStorage.cs | 1 + .../FsSystem/ConcatenationStorageBuilder.cs | 1 + src/LibHac/FsSystem/Delta.cs | 1 + src/LibHac/FsSystem/DirectorySaveDataFile.cs | 1 + .../FsSystem/DirectorySaveDataFileSystem.cs | 1 + src/LibHac/FsSystem/DirectoryUtils.cs | 1 + src/LibHac/FsSystem/FileBase.cs | 1 + src/LibHac/FsSystem/FileReader.cs | 1 + src/LibHac/FsSystem/FileStorage.cs | 1 + src/LibHac/FsSystem/FileSystemExtensions.cs | 1 + .../HierarchicalIntegrityVerificationStorage.cs | 1 + src/LibHac/FsSystem/IndirectStorage.cs | 1 + .../FsSystem/IntegrityVerificationStorage.cs | 1 + src/LibHac/FsSystem/LayeredFileSystem.cs | 1 + src/LibHac/FsSystem/LayeredFileSystemDirectory.cs | 1 + src/LibHac/FsSystem/LocalDirectory.cs | 1 + src/LibHac/FsSystem/LocalFile.cs | 1 + src/LibHac/FsSystem/LocalFileSystem.cs | 1 + src/LibHac/FsSystem/MemoryStorage.cs | 1 + src/LibHac/FsSystem/NcaUtils/Nca.cs | 1 + src/LibHac/FsSystem/NcaUtils/NcaExtensions.cs | 1 + src/LibHac/FsSystem/NcaUtils/NcaHeader.cs | 1 + src/LibHac/FsSystem/NullFile.cs | 1 + src/LibHac/FsSystem/NullStorage.cs | 1 + src/LibHac/FsSystem/NxFileStream.cs | 1 + src/LibHac/FsSystem/PartitionDirectory.cs | 1 + src/LibHac/FsSystem/PartitionFile.cs | 1 + src/LibHac/FsSystem/PartitionFileSystem.cs | 1 + src/LibHac/FsSystem/PartitionFileSystemBuilder.cs | 1 + src/LibHac/FsSystem/PathTools.cs | 1 + src/LibHac/FsSystem/ReadOnlyFile.cs | 1 + src/LibHac/FsSystem/ReadOnlyFileSystem.cs | 1 + .../FsSystem/RomFs/HierarchicalRomFileTable.cs | 1 + src/LibHac/FsSystem/RomFs/RomFsBuilder.cs | 1 + src/LibHac/FsSystem/RomFs/RomFsDictionary.cs | 1 + src/LibHac/FsSystem/RomFs/RomFsDirectory.cs | 1 + src/LibHac/FsSystem/RomFs/RomFsFile.cs | 1 + src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs | 1 + src/LibHac/FsSystem/Save/AllocationTable.cs | 1 + .../FsSystem/Save/AllocationTableStorage.cs | 1 + src/LibHac/FsSystem/Save/DuplexBitmap.cs | 1 + src/LibHac/FsSystem/Save/DuplexStorage.cs | 1 + src/LibHac/FsSystem/Save/Header.cs | 1 + .../FsSystem/Save/HierarchicalDuplexStorage.cs | 1 + .../FsSystem/Save/HierarchicalSaveFileTable.cs | 1 + src/LibHac/FsSystem/Save/JournalMap.cs | 1 + src/LibHac/FsSystem/Save/JournalStorage.cs | 1 + src/LibHac/FsSystem/Save/RemapStorage.cs | 1 + src/LibHac/FsSystem/Save/SaveDataDirectory.cs | 1 + src/LibHac/FsSystem/Save/SaveDataFileSystem.cs | 1 + .../FsSystem/Save/SaveDataFileSystemCore.cs | 1 + src/LibHac/FsSystem/Save/SaveFsList.cs | 1 + src/LibHac/FsSystem/Save/SaveResults.cs | 4 +++- src/LibHac/FsSystem/SaveDataCreateInfo.cs | 10 ---------- src/LibHac/FsSystem/SaveMetaCreateInfo.cs | 11 ----------- src/LibHac/FsSystem/SectorStorage.cs | 1 + src/LibHac/FsSystem/StorageBase.cs | 1 + src/LibHac/FsSystem/StorageExtensions.cs | 1 + src/LibHac/FsSystem/StorageFile.cs | 1 + src/LibHac/FsSystem/StorageStream.cs | 1 + src/LibHac/FsSystem/StreamFile.cs | 2 +- src/LibHac/FsSystem/SubStorage.cs | 1 + src/LibHac/FsSystem/SubdirectoryFileSystem.cs | 1 + src/LibHac/Kip.cs | 1 + src/LibHac/Ncm/IContentStorage.cs | 2 +- src/LibHac/Nro.cs | 1 + src/LibHac/Nso.cs | 1 + src/LibHac/Package1.cs | 1 + src/LibHac/Package2.cs | 1 + src/LibHac/SwitchFs.cs | 1 + src/LibHac/Xci.cs | 3 ++- src/hactoolnet/ProcessBench.cs | 1 + src/hactoolnet/ProcessDelta.cs | 1 + src/hactoolnet/ProcessFsBuild.cs | 1 + src/hactoolnet/ProcessPfs.cs | 1 + src/hactoolnet/ProcessRomfs.cs | 1 + src/hactoolnet/ProcessSwitchFs.cs | 1 + src/hactoolnet/ProcessXci.cs | 1 + 138 files changed, 155 insertions(+), 73 deletions(-) rename src/LibHac/{FsSystem => Fs}/DirectoryEntry.cs (96%) rename src/LibHac/{FsSystem => Fs}/FileTimeStamp.cs (82%) rename src/LibHac/{FsSystem => Fs}/FsEnums.cs (98%) rename src/LibHac/{FsSystem => Fs}/IAttributeFileSystem.cs (89%) rename src/LibHac/{FsSystem => Fs}/IDirectory.cs (98%) rename src/LibHac/{FsSystem => Fs}/IFile.cs (98%) rename src/LibHac/{FsSystem => Fs}/IFileSystem.cs (99%) rename src/LibHac/{FsSystem => Fs}/IStorage.cs (98%) rename src/LibHac/{FsSystem => Fs}/ResultFs.cs (99%) rename src/LibHac/{FsSystem => Fs}/ResultRangeFs.cs (97%) rename src/LibHac/{FsSystem => Fs}/RightsId.cs (98%) rename src/LibHac/{FsSystem => Fs}/SaveDataAttribute.cs (99%) rename src/LibHac/{FsSystem => Fs}/SaveDataStructs.cs (87%) rename src/LibHac/{FsSystem => Fs}/UserId.cs (98%) rename src/LibHac/{FsSystem => FsService}/SaveIndexerStruct.cs (98%) delete mode 100644 src/LibHac/FsSystem/SaveDataCreateInfo.cs delete mode 100644 src/LibHac/FsSystem/SaveMetaCreateInfo.cs diff --git a/src/LibHac/Common/Id128.cs b/src/LibHac/Common/Id128.cs index 8b7f8529..a0289014 100644 --- a/src/LibHac/Common/Id128.cs +++ b/src/LibHac/Common/Id128.cs @@ -35,7 +35,7 @@ namespace LibHac.Common public override bool Equals(object obj) { - return obj is FsSystem.UserId other && Equals(other); + return obj is Id128 other && Equals(other); } public override int GetHashCode() diff --git a/src/LibHac/Fs/Accessors/MountTable.cs b/src/LibHac/Fs/Accessors/MountTable.cs index 06469eab..ec9f94cb 100644 --- a/src/LibHac/Fs/Accessors/MountTable.cs +++ b/src/LibHac/Fs/Accessors/MountTable.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using LibHac.FsSystem; namespace LibHac.Fs.Accessors { diff --git a/src/LibHac/Fs/ContentStorage.cs b/src/LibHac/Fs/ContentStorage.cs index 25a8da2a..c9545d71 100644 --- a/src/LibHac/Fs/ContentStorage.cs +++ b/src/LibHac/Fs/ContentStorage.cs @@ -1,6 +1,5 @@ using System; using LibHac.Common; -using LibHac.FsSystem; using LibHac.FsService; namespace LibHac.Fs diff --git a/src/LibHac/FsSystem/DirectoryEntry.cs b/src/LibHac/Fs/DirectoryEntry.cs similarity index 96% rename from src/LibHac/FsSystem/DirectoryEntry.cs rename to src/LibHac/Fs/DirectoryEntry.cs index 332e4f6d..1d60e85d 100644 --- a/src/LibHac/FsSystem/DirectoryEntry.cs +++ b/src/LibHac/Fs/DirectoryEntry.cs @@ -1,8 +1,9 @@ using System; using System.Runtime.InteropServices; using LibHac.Common; +using LibHac.FsSystem; -namespace LibHac.FsSystem +namespace LibHac.Fs { public class DirectoryEntryEx { diff --git a/src/LibHac/Fs/FileSystemClient.Directory.cs b/src/LibHac/Fs/FileSystemClient.Directory.cs index 6d29c054..90253dfe 100644 --- a/src/LibHac/Fs/FileSystemClient.Directory.cs +++ b/src/LibHac/Fs/FileSystemClient.Directory.cs @@ -1,5 +1,4 @@ using System; -using LibHac.FsSystem; namespace LibHac.Fs { diff --git a/src/LibHac/Fs/FileSystemClient.Mount.cs b/src/LibHac/Fs/FileSystemClient.Mount.cs index 0ccb6440..4eed577d 100644 --- a/src/LibHac/Fs/FileSystemClient.Mount.cs +++ b/src/LibHac/Fs/FileSystemClient.Mount.cs @@ -1,5 +1,4 @@ using LibHac.Common; -using LibHac.FsSystem; using LibHac.FsService; namespace LibHac.Fs diff --git a/src/LibHac/Fs/FileSystemClient.cs b/src/LibHac/Fs/FileSystemClient.cs index 3c4f5ff9..999aa7a6 100644 --- a/src/LibHac/Fs/FileSystemClient.cs +++ b/src/LibHac/Fs/FileSystemClient.cs @@ -1,5 +1,4 @@ using LibHac.Common; -using LibHac.FsSystem; using LibHac.FsService; namespace LibHac.Fs diff --git a/src/LibHac/FsSystem/FileTimeStamp.cs b/src/LibHac/Fs/FileTimeStamp.cs similarity index 82% rename from src/LibHac/FsSystem/FileTimeStamp.cs rename to src/LibHac/Fs/FileTimeStamp.cs index 0dbe64eb..74aff00a 100644 --- a/src/LibHac/FsSystem/FileTimeStamp.cs +++ b/src/LibHac/Fs/FileTimeStamp.cs @@ -1,4 +1,4 @@ -namespace LibHac.FsSystem +namespace LibHac.Fs { public struct FileTimeStampRaw { diff --git a/src/LibHac/FsSystem/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs similarity index 98% rename from src/LibHac/FsSystem/FsEnums.cs rename to src/LibHac/Fs/FsEnums.cs index b00cf136..223f36fb 100644 --- a/src/LibHac/FsSystem/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -1,4 +1,4 @@ -namespace LibHac.FsSystem +namespace LibHac.Fs { public enum BisPartitionId { diff --git a/src/LibHac/FsSystem/IAttributeFileSystem.cs b/src/LibHac/Fs/IAttributeFileSystem.cs similarity index 89% rename from src/LibHac/FsSystem/IAttributeFileSystem.cs rename to src/LibHac/Fs/IAttributeFileSystem.cs index e7688a1b..e5a4858d 100644 --- a/src/LibHac/FsSystem/IAttributeFileSystem.cs +++ b/src/LibHac/Fs/IAttributeFileSystem.cs @@ -1,4 +1,4 @@ -namespace LibHac.FsSystem +namespace LibHac.Fs { public interface IAttributeFileSystem : IFileSystem { diff --git a/src/LibHac/FsSystem/IDirectory.cs b/src/LibHac/Fs/IDirectory.cs similarity index 98% rename from src/LibHac/FsSystem/IDirectory.cs rename to src/LibHac/Fs/IDirectory.cs index d9355ec4..401d26d7 100644 --- a/src/LibHac/FsSystem/IDirectory.cs +++ b/src/LibHac/Fs/IDirectory.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.FsSystem +namespace LibHac.Fs { /// /// Provides an interface for enumerating the child entries of a directory. diff --git a/src/LibHac/FsSystem/IFile.cs b/src/LibHac/Fs/IFile.cs similarity index 98% rename from src/LibHac/FsSystem/IFile.cs rename to src/LibHac/Fs/IFile.cs index 6e81af02..bec15141 100644 --- a/src/LibHac/FsSystem/IFile.cs +++ b/src/LibHac/Fs/IFile.cs @@ -1,6 +1,7 @@ using System; +using LibHac.FsSystem; -namespace LibHac.FsSystem +namespace LibHac.Fs { /// /// Provides an interface for reading and writing a sequence of bytes. diff --git a/src/LibHac/FsSystem/IFileSystem.cs b/src/LibHac/Fs/IFileSystem.cs similarity index 99% rename from src/LibHac/FsSystem/IFileSystem.cs rename to src/LibHac/Fs/IFileSystem.cs index 9ff76341..5e6275b6 100644 --- a/src/LibHac/FsSystem/IFileSystem.cs +++ b/src/LibHac/Fs/IFileSystem.cs @@ -1,6 +1,7 @@ using System; +using LibHac.FsSystem; -namespace LibHac.FsSystem +namespace LibHac.Fs { /// /// Provides an interface for accessing a file system. / is used as the path delimiter. diff --git a/src/LibHac/FsSystem/IStorage.cs b/src/LibHac/Fs/IStorage.cs similarity index 98% rename from src/LibHac/FsSystem/IStorage.cs rename to src/LibHac/Fs/IStorage.cs index 6f38528b..8f0a1b47 100644 --- a/src/LibHac/FsSystem/IStorage.cs +++ b/src/LibHac/Fs/IStorage.cs @@ -1,6 +1,6 @@ using System; -namespace LibHac.FsSystem +namespace LibHac.Fs { /// /// Provides an interface for reading and writing a sequence of bytes. diff --git a/src/LibHac/Fs/MountHelpers.cs b/src/LibHac/Fs/MountHelpers.cs index 5d46e223..33ecb09e 100644 --- a/src/LibHac/Fs/MountHelpers.cs +++ b/src/LibHac/Fs/MountHelpers.cs @@ -1,5 +1,4 @@ using LibHac.Common; -using LibHac.FsSystem; namespace LibHac.Fs { @@ -24,6 +23,7 @@ namespace LibHac.Fs return Result.Success; } + // ReSharper disable once UnusedParameter.Local private static bool CheckMountNameImpl(U8Span name) { // Todo diff --git a/src/LibHac/FsSystem/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs similarity index 99% rename from src/LibHac/FsSystem/ResultFs.cs rename to src/LibHac/Fs/ResultFs.cs index 0f064a80..fcc8eb68 100644 --- a/src/LibHac/FsSystem/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -1,4 +1,4 @@ -namespace LibHac.FsSystem +namespace LibHac.Fs { public class ResultFs { diff --git a/src/LibHac/FsSystem/ResultRangeFs.cs b/src/LibHac/Fs/ResultRangeFs.cs similarity index 97% rename from src/LibHac/FsSystem/ResultRangeFs.cs rename to src/LibHac/Fs/ResultRangeFs.cs index 3ffd032d..f0289aeb 100644 --- a/src/LibHac/FsSystem/ResultRangeFs.cs +++ b/src/LibHac/Fs/ResultRangeFs.cs @@ -1,4 +1,4 @@ -namespace LibHac.FsSystem +namespace LibHac.Fs { public static class ResultRangeFs { diff --git a/src/LibHac/FsSystem/RightsId.cs b/src/LibHac/Fs/RightsId.cs similarity index 98% rename from src/LibHac/FsSystem/RightsId.cs rename to src/LibHac/Fs/RightsId.cs index d3ac5836..11f0969d 100644 --- a/src/LibHac/FsSystem/RightsId.cs +++ b/src/LibHac/Fs/RightsId.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using LibHac.Common; -namespace LibHac.FsSystem +namespace LibHac.Fs { [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct RightsId : IEquatable, IComparable, IComparable diff --git a/src/LibHac/FsSystem/SaveDataAttribute.cs b/src/LibHac/Fs/SaveDataAttribute.cs similarity index 99% rename from src/LibHac/FsSystem/SaveDataAttribute.cs rename to src/LibHac/Fs/SaveDataAttribute.cs index d501602a..3fd4614d 100644 --- a/src/LibHac/FsSystem/SaveDataAttribute.cs +++ b/src/LibHac/Fs/SaveDataAttribute.cs @@ -3,7 +3,7 @@ using System.Buffers.Binary; using LibHac.FsSystem.Save; using LibHac.Kvdb; -namespace LibHac.FsSystem +namespace LibHac.Fs { public class SaveDataAttribute : IComparable, IComparable, IEquatable, IExportable { diff --git a/src/LibHac/FsSystem/SaveDataStructs.cs b/src/LibHac/Fs/SaveDataStructs.cs similarity index 87% rename from src/LibHac/FsSystem/SaveDataStructs.cs rename to src/LibHac/Fs/SaveDataStructs.cs index ee2a2d7c..adcd0569 100644 --- a/src/LibHac/FsSystem/SaveDataStructs.cs +++ b/src/LibHac/Fs/SaveDataStructs.cs @@ -4,7 +4,7 @@ using LibHac.Common; using LibHac.FsSystem.Save; using LibHac.Ncm; -namespace LibHac.FsSystem +namespace LibHac.Fs { [StructLayout(LayoutKind.Explicit, Size = 0x40)] public struct SaveDataAttribute2 @@ -67,4 +67,17 @@ namespace LibHac.FsSystem public Span Hash => SpanHelpers.CreateSpan(ref _hashStart, HashLength); } + + [StructLayout(LayoutKind.Explicit, Size = 0x10)] + public struct SaveMetaCreateInfo + { + [FieldOffset(0)] public int Size; + [FieldOffset(4)] public SaveMetaType Type; + } + + [StructLayout(LayoutKind.Explicit, Size = 0x40)] + public struct SaveDataCreateInfo + { + // Todo + } } diff --git a/src/LibHac/FsSystem/UserId.cs b/src/LibHac/Fs/UserId.cs similarity index 98% rename from src/LibHac/FsSystem/UserId.cs rename to src/LibHac/Fs/UserId.cs index 7332102a..4a14fc46 100644 --- a/src/LibHac/FsSystem/UserId.cs +++ b/src/LibHac/Fs/UserId.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using LibHac.Common; -namespace LibHac.FsSystem +namespace LibHac.Fs { [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct UserId : IEquatable, IComparable, IComparable diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs index 9ba8578a..edba44ca 100644 --- a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs @@ -1,5 +1,5 @@ using System.Diagnostics; -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs index 0fd195ab..1e6ebe98 100644 --- a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs @@ -1,5 +1,5 @@ using System.Diagnostics; -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs index b5392d4f..b27c6aff 100644 --- a/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedSdFileSystemCreator.cs @@ -1,5 +1,5 @@ using System; -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs b/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs index b1798719..7c6c20f9 100644 --- a/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EncryptedFileSystemCreator.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; using LibHac.FsSystem; namespace LibHac.FsService.Creators diff --git a/src/LibHac/FsService/Creators/FileSystemCreators.cs b/src/LibHac/FsService/Creators/FileSystemCreators.cs index 0539a95c..2afa63df 100644 --- a/src/LibHac/FsService/Creators/FileSystemCreators.cs +++ b/src/LibHac/FsService/Creators/FileSystemCreators.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs b/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs index 397da7ef..e7e6df62 100644 --- a/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs +++ b/src/LibHac/FsService/Creators/IBuiltInStorageCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs b/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs index 07c4b68d..b94ca90a 100644 --- a/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IBuiltInStorageFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs b/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs index 36f73579..f6cfde96 100644 --- a/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IEncryptedFileSystemCreator.cs @@ -1,5 +1,5 @@ using System; -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs b/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs index 8b139d5c..b86fac56 100644 --- a/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IFatFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs b/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs index c57357dd..550ce9c6 100644 --- a/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IGameCardFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs b/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs index b6afd9e5..e5fdfc19 100644 --- a/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs +++ b/src/LibHac/FsService/Creators/IGameCardStorageCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs index 809fbef0..d7c50ff5 100644 --- a/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs b/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs index 14b0e961..403dbe01 100644 --- a/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs +++ b/src/LibHac/FsService/Creators/IMemoryStorageCreator.cs @@ -1,5 +1,5 @@ using System; -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs b/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs index d6b43d6b..af99e8cd 100644 --- a/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IPartitionFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs b/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs index 3429397f..b2ea3957 100644 --- a/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IRomFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs index 854fb051..29f45fb5 100644 --- a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs @@ -1,5 +1,6 @@ using System; using LibHac.Common; +using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.Save; diff --git a/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs index 0a0765dc..041f0217 100644 --- a/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISdFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/ISdStorageCreator.cs b/src/LibHac/FsService/Creators/ISdStorageCreator.cs index bb2c2dac..691359bb 100644 --- a/src/LibHac/FsService/Creators/ISdStorageCreator.cs +++ b/src/LibHac/FsService/Creators/ISdStorageCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs b/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs index 92378a75..2d6d8fb3 100644 --- a/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs +++ b/src/LibHac/FsService/Creators/IStorageOnNcaCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; using LibHac.FsSystem.NcaUtils; namespace LibHac.FsService.Creators diff --git a/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs index 1ac8a48a..3bae3cb7 100644 --- a/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs index 59eed39a..e0858de4 100644 --- a/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs @@ -1,4 +1,4 @@ -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs index fed3898c..06983e72 100644 --- a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs @@ -1,4 +1,5 @@ -using LibHac.FsSystem; +using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac.FsService.Creators { diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index a015e579..a579ea05 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -10,6 +10,7 @@ namespace LibHac.FsService private FileSystemProxyCore FsProxyCore { get; } /// The client instance to be used for internal operations like save indexer access. + // ReSharper disable once UnusedAutoPropertyAccessor.Local private FileSystemClient FsClient { get; } public long CurrentProcess { get; private set; } @@ -110,7 +111,7 @@ namespace LibHac.FsService if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log(); - Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out ulong saveDataId, spaceId, + Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out _, spaceId, attribute, false, true); if (rc.IsFailure()) return rc; @@ -159,6 +160,7 @@ namespace LibHac.FsService if (saveDataId != SaveIndexerId) { + // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (hasFixedId) { // todo: remove save indexer entry diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 8463c2a3..3534074d 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.Save; using LibHac.FsService.Creators; @@ -157,9 +158,8 @@ namespace LibHac.FsService // Missing save FS cache lookup - rc = FsCreators.SaveDataFileSystemCreator.Create(out IFileSystem saveFs, - out ISaveDataExtraDataAccessor extraDataAccessor, saveDirFs, saveDataId, allowDirectorySaveData, - useDeviceUniqueMac, type, null); + rc = FsCreators.SaveDataFileSystemCreator.Create(out IFileSystem saveFs, out _, saveDirFs, saveDataId, + allowDirectorySaveData, useDeviceUniqueMac, type, null); if (rc.IsFailure()) return rc; diff --git a/src/LibHac/FsService/IFileSystemProxy.cs b/src/LibHac/FsService/IFileSystemProxy.cs index 708d3155..2b5791ca 100644 --- a/src/LibHac/FsService/IFileSystemProxy.cs +++ b/src/LibHac/FsService/IFileSystemProxy.cs @@ -1,5 +1,6 @@ using System; using LibHac.Common; +using LibHac.Fs; using LibHac.FsSystem; using LibHac.Ncm; using LibHac.Spl; diff --git a/src/LibHac/FsSystem/SaveIndexerStruct.cs b/src/LibHac/FsService/SaveIndexerStruct.cs similarity index 98% rename from src/LibHac/FsSystem/SaveIndexerStruct.cs rename to src/LibHac/FsService/SaveIndexerStruct.cs index b51dfa6f..e78ff3a6 100644 --- a/src/LibHac/FsSystem/SaveIndexerStruct.cs +++ b/src/LibHac/FsService/SaveIndexerStruct.cs @@ -2,7 +2,7 @@ using System.Buffers.Binary; using LibHac.Kvdb; -namespace LibHac.FsSystem +namespace LibHac.FsService { public class SaveIndexerStruct : IExportable { diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs index 6519cf26..195549e8 100644 --- a/src/LibHac/FsService/Util.cs +++ b/src/LibHac/FsService/Util.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; using LibHac.FsSystem; namespace LibHac.FsService diff --git a/src/LibHac/FsSystem/Aes128CtrExStorage.cs b/src/LibHac/FsSystem/Aes128CtrExStorage.cs index eebe24ff..d91b889b 100644 --- a/src/LibHac/FsSystem/Aes128CtrExStorage.cs +++ b/src/LibHac/FsSystem/Aes128CtrExStorage.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/Aes128CtrStorage.cs b/src/LibHac/FsSystem/Aes128CtrStorage.cs index 0437c092..e413bff3 100644 --- a/src/LibHac/FsSystem/Aes128CtrStorage.cs +++ b/src/LibHac/FsSystem/Aes128CtrStorage.cs @@ -1,6 +1,7 @@ using System; using System.Buffers; using System.Buffers.Binary; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/Aes128XtsStorage.cs b/src/LibHac/FsSystem/Aes128XtsStorage.cs index a0844d61..865e366f 100644 --- a/src/LibHac/FsSystem/Aes128XtsStorage.cs +++ b/src/LibHac/FsSystem/Aes128XtsStorage.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/AesXtsDirectory.cs b/src/LibHac/FsSystem/AesXtsDirectory.cs index bb7d4415..c262ae6d 100644 --- a/src/LibHac/FsSystem/AesXtsDirectory.cs +++ b/src/LibHac/FsSystem/AesXtsDirectory.cs @@ -1,5 +1,6 @@ using System; using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/AesXtsFile.cs b/src/LibHac/FsSystem/AesXtsFile.cs index 683c2341..bd70578f 100644 --- a/src/LibHac/FsSystem/AesXtsFile.cs +++ b/src/LibHac/FsSystem/AesXtsFile.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/AesXtsFileHeader.cs b/src/LibHac/FsSystem/AesXtsFileHeader.cs index da830f82..89233eab 100644 --- a/src/LibHac/FsSystem/AesXtsFileHeader.cs +++ b/src/LibHac/FsSystem/AesXtsFileHeader.cs @@ -2,6 +2,7 @@ using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/AesXtsFileSystem.cs b/src/LibHac/FsSystem/AesXtsFileSystem.cs index fa33b06a..a5de6e98 100644 --- a/src/LibHac/FsSystem/AesXtsFileSystem.cs +++ b/src/LibHac/FsSystem/AesXtsFileSystem.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/BucketTree.cs b/src/LibHac/FsSystem/BucketTree.cs index a9095a77..85f6608e 100644 --- a/src/LibHac/FsSystem/BucketTree.cs +++ b/src/LibHac/FsSystem/BucketTree.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/CachedStorage.cs b/src/LibHac/FsSystem/CachedStorage.cs index f73fffb2..bc6485fb 100644 --- a/src/LibHac/FsSystem/CachedStorage.cs +++ b/src/LibHac/FsSystem/CachedStorage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/ConcatenationDirectory.cs b/src/LibHac/FsSystem/ConcatenationDirectory.cs index 76587582..13b60cc7 100644 --- a/src/LibHac/FsSystem/ConcatenationDirectory.cs +++ b/src/LibHac/FsSystem/ConcatenationDirectory.cs @@ -1,6 +1,6 @@ using System; using LibHac.Common; - +using LibHac.Fs; #if CROSS_PLATFORM using System.Runtime.InteropServices; #endif diff --git a/src/LibHac/FsSystem/ConcatenationFile.cs b/src/LibHac/FsSystem/ConcatenationFile.cs index 887ac26a..88ee7589 100644 --- a/src/LibHac/FsSystem/ConcatenationFile.cs +++ b/src/LibHac/FsSystem/ConcatenationFile.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/ConcatenationFileSystem.cs b/src/LibHac/FsSystem/ConcatenationFileSystem.cs index c7c18686..f9683629 100644 --- a/src/LibHac/FsSystem/ConcatenationFileSystem.cs +++ b/src/LibHac/FsSystem/ConcatenationFileSystem.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; - +using LibHac.Fs; #if CROSS_PLATFORM using System.Runtime.InteropServices; #endif diff --git a/src/LibHac/FsSystem/ConcatenationStorage.cs b/src/LibHac/FsSystem/ConcatenationStorage.cs index 7d695dc5..9bce2554 100644 --- a/src/LibHac/FsSystem/ConcatenationStorage.cs +++ b/src/LibHac/FsSystem/ConcatenationStorage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/ConcatenationStorageBuilder.cs b/src/LibHac/FsSystem/ConcatenationStorageBuilder.cs index ff2da7b8..afe464bd 100644 --- a/src/LibHac/FsSystem/ConcatenationStorageBuilder.cs +++ b/src/LibHac/FsSystem/ConcatenationStorageBuilder.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/Delta.cs b/src/LibHac/FsSystem/Delta.cs index 9ca03cef..a3869dbe 100644 --- a/src/LibHac/FsSystem/Delta.cs +++ b/src/LibHac/FsSystem/Delta.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/DirectorySaveDataFile.cs b/src/LibHac/FsSystem/DirectorySaveDataFile.cs index 62e384ce..09c61ba9 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFile.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFile.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs index a782dc2e..cfa98fbe 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/DirectoryUtils.cs b/src/LibHac/FsSystem/DirectoryUtils.cs index b5bba902..f28e5896 100644 --- a/src/LibHac/FsSystem/DirectoryUtils.cs +++ b/src/LibHac/FsSystem/DirectoryUtils.cs @@ -1,5 +1,6 @@ using System; using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/FileBase.cs b/src/LibHac/FsSystem/FileBase.cs index 742853c2..33b30489 100644 --- a/src/LibHac/FsSystem/FileBase.cs +++ b/src/LibHac/FsSystem/FileBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/FileReader.cs b/src/LibHac/FsSystem/FileReader.cs index cf4607b4..b1c79db8 100644 --- a/src/LibHac/FsSystem/FileReader.cs +++ b/src/LibHac/FsSystem/FileReader.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/FileStorage.cs b/src/LibHac/FsSystem/FileStorage.cs index 21bf43c9..a1865732 100644 --- a/src/LibHac/FsSystem/FileStorage.cs +++ b/src/LibHac/FsSystem/FileStorage.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/FileSystemExtensions.cs b/src/LibHac/FsSystem/FileSystemExtensions.cs index 9ed1571a..fd7ba09b 100644 --- a/src/LibHac/FsSystem/FileSystemExtensions.cs +++ b/src/LibHac/FsSystem/FileSystemExtensions.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Collections.Generic; using System.IO; using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs b/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs index 709eca51..4d6d14be 100644 --- a/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs +++ b/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Text; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/IndirectStorage.cs b/src/LibHac/FsSystem/IndirectStorage.cs index 850b401f..e2c0dc05 100644 --- a/src/LibHac/FsSystem/IndirectStorage.cs +++ b/src/LibHac/FsSystem/IndirectStorage.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/IntegrityVerificationStorage.cs b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs index 5e7bd8ce..49d14636 100644 --- a/src/LibHac/FsSystem/IntegrityVerificationStorage.cs +++ b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs @@ -2,6 +2,7 @@ using System.Buffers; using System.IO; using System.Security.Cryptography; +using LibHac.Fs; using LibHac.FsSystem.Save; namespace LibHac.FsSystem diff --git a/src/LibHac/FsSystem/LayeredFileSystem.cs b/src/LibHac/FsSystem/LayeredFileSystem.cs index 47e88d4a..fe29a3fb 100644 --- a/src/LibHac/FsSystem/LayeredFileSystem.cs +++ b/src/LibHac/FsSystem/LayeredFileSystem.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/LayeredFileSystemDirectory.cs b/src/LibHac/FsSystem/LayeredFileSystemDirectory.cs index 3c23e239..244beeed 100644 --- a/src/LibHac/FsSystem/LayeredFileSystemDirectory.cs +++ b/src/LibHac/FsSystem/LayeredFileSystemDirectory.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/LocalDirectory.cs b/src/LibHac/FsSystem/LocalDirectory.cs index 02f478be..c49b16ab 100644 --- a/src/LibHac/FsSystem/LocalDirectory.cs +++ b/src/LibHac/FsSystem/LocalDirectory.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/LocalFile.cs b/src/LibHac/FsSystem/LocalFile.cs index 4d7abd4b..92fc844b 100644 --- a/src/LibHac/FsSystem/LocalFile.cs +++ b/src/LibHac/FsSystem/LocalFile.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/LocalFileSystem.cs b/src/LibHac/FsSystem/LocalFileSystem.cs index dea5ba32..0e3431e5 100644 --- a/src/LibHac/FsSystem/LocalFileSystem.cs +++ b/src/LibHac/FsSystem/LocalFileSystem.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Security; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/MemoryStorage.cs b/src/LibHac/FsSystem/MemoryStorage.cs index 9b139158..8ec783a5 100644 --- a/src/LibHac/FsSystem/MemoryStorage.cs +++ b/src/LibHac/FsSystem/MemoryStorage.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/NcaUtils/Nca.cs b/src/LibHac/FsSystem/NcaUtils/Nca.cs index 9cb388e6..f10ae281 100644 --- a/src/LibHac/FsSystem/NcaUtils/Nca.cs +++ b/src/LibHac/FsSystem/NcaUtils/Nca.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using LibHac.Fs; using LibHac.FsSystem.RomFs; namespace LibHac.FsSystem.NcaUtils diff --git a/src/LibHac/FsSystem/NcaUtils/NcaExtensions.cs b/src/LibHac/FsSystem/NcaUtils/NcaExtensions.cs index 5138a917..b9ddfc7f 100644 --- a/src/LibHac/FsSystem/NcaUtils/NcaExtensions.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Buffers.Binary; using System.Diagnostics; +using LibHac.Fs; namespace LibHac.FsSystem.NcaUtils { diff --git a/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs b/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs index 6f19818b..7445129b 100644 --- a/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs @@ -2,6 +2,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using LibHac.Fs; namespace LibHac.FsSystem.NcaUtils { diff --git a/src/LibHac/FsSystem/NullFile.cs b/src/LibHac/FsSystem/NullFile.cs index 44847aa3..a3d12591 100644 --- a/src/LibHac/FsSystem/NullFile.cs +++ b/src/LibHac/FsSystem/NullFile.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/NullStorage.cs b/src/LibHac/FsSystem/NullStorage.cs index a019e898..ba78a51b 100644 --- a/src/LibHac/FsSystem/NullStorage.cs +++ b/src/LibHac/FsSystem/NullStorage.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/NxFileStream.cs b/src/LibHac/FsSystem/NxFileStream.cs index 7d6dd02b..48b5d99f 100644 --- a/src/LibHac/FsSystem/NxFileStream.cs +++ b/src/LibHac/FsSystem/NxFileStream.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/PartitionDirectory.cs b/src/LibHac/FsSystem/PartitionDirectory.cs index 518c1350..c66de8f2 100644 --- a/src/LibHac/FsSystem/PartitionDirectory.cs +++ b/src/LibHac/FsSystem/PartitionDirectory.cs @@ -2,6 +2,7 @@ using System.IO; using System.Text; using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/PartitionFile.cs b/src/LibHac/FsSystem/PartitionFile.cs index 62a6c213..0c734f13 100644 --- a/src/LibHac/FsSystem/PartitionFile.cs +++ b/src/LibHac/FsSystem/PartitionFile.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/PartitionFileSystem.cs b/src/LibHac/FsSystem/PartitionFileSystem.cs index 4012cfba..ece8b637 100644 --- a/src/LibHac/FsSystem/PartitionFileSystem.cs +++ b/src/LibHac/FsSystem/PartitionFileSystem.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs b/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs index bbe4a0b4..12cf4c82 100644 --- a/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs +++ b/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/PathTools.cs b/src/LibHac/FsSystem/PathTools.cs index bb7cf41a..3a0fcd51 100644 --- a/src/LibHac/FsSystem/PathTools.cs +++ b/src/LibHac/FsSystem/PathTools.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; +using LibHac.Fs; #if HAS_FILE_SYSTEM_NAME using System.IO.Enumeration; diff --git a/src/LibHac/FsSystem/ReadOnlyFile.cs b/src/LibHac/FsSystem/ReadOnlyFile.cs index c93be5ba..07611c3f 100644 --- a/src/LibHac/FsSystem/ReadOnlyFile.cs +++ b/src/LibHac/FsSystem/ReadOnlyFile.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/ReadOnlyFileSystem.cs b/src/LibHac/FsSystem/ReadOnlyFileSystem.cs index a3c35b94..66fc9e18 100644 --- a/src/LibHac/FsSystem/ReadOnlyFileSystem.cs +++ b/src/LibHac/FsSystem/ReadOnlyFileSystem.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/RomFs/HierarchicalRomFileTable.cs b/src/LibHac/FsSystem/RomFs/HierarchicalRomFileTable.cs index c6476ec5..8d455b2a 100644 --- a/src/LibHac/FsSystem/RomFs/HierarchicalRomFileTable.cs +++ b/src/LibHac/FsSystem/RomFs/HierarchicalRomFileTable.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using LibHac.Fs; namespace LibHac.FsSystem.RomFs { diff --git a/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs b/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs index 3ec7cbb8..5f95e172 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using LibHac.Fs; namespace LibHac.FsSystem.RomFs { diff --git a/src/LibHac/FsSystem/RomFs/RomFsDictionary.cs b/src/LibHac/FsSystem/RomFs/RomFsDictionary.cs index d93970c9..9989f8a7 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsDictionary.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsDictionary.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using LibHac.Fs; namespace LibHac.FsSystem.RomFs { diff --git a/src/LibHac/FsSystem/RomFs/RomFsDirectory.cs b/src/LibHac/FsSystem/RomFs/RomFsDirectory.cs index 3d0ae58a..12c19acb 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsDirectory.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsDirectory.cs @@ -1,6 +1,7 @@ using System; using System.Text; using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem.RomFs { diff --git a/src/LibHac/FsSystem/RomFs/RomFsFile.cs b/src/LibHac/FsSystem/RomFs/RomFsFile.cs index 42aa8493..d069d860 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsFile.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsFile.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem.RomFs { diff --git a/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs b/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs index b2b6f718..cdd8507d 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem.RomFs { diff --git a/src/LibHac/FsSystem/Save/AllocationTable.cs b/src/LibHac/FsSystem/Save/AllocationTable.cs index a09e9deb..57c221b3 100644 --- a/src/LibHac/FsSystem/Save/AllocationTable.cs +++ b/src/LibHac/FsSystem/Save/AllocationTable.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/AllocationTableStorage.cs b/src/LibHac/FsSystem/Save/AllocationTableStorage.cs index cf66ff44..1e8b60c0 100644 --- a/src/LibHac/FsSystem/Save/AllocationTableStorage.cs +++ b/src/LibHac/FsSystem/Save/AllocationTableStorage.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/DuplexBitmap.cs b/src/LibHac/FsSystem/Save/DuplexBitmap.cs index e76d2492..993eb7d5 100644 --- a/src/LibHac/FsSystem/Save/DuplexBitmap.cs +++ b/src/LibHac/FsSystem/Save/DuplexBitmap.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/DuplexStorage.cs b/src/LibHac/FsSystem/Save/DuplexStorage.cs index 25206542..6ac63544 100644 --- a/src/LibHac/FsSystem/Save/DuplexStorage.cs +++ b/src/LibHac/FsSystem/Save/DuplexStorage.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/Header.cs b/src/LibHac/FsSystem/Save/Header.cs index 7e8b908b..98a98f4f 100644 --- a/src/LibHac/FsSystem/Save/Header.cs +++ b/src/LibHac/FsSystem/Save/Header.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs b/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs index 0c4c212a..e942fbd6 100644 --- a/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs +++ b/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs b/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs index 359bea1b..236af46b 100644 --- a/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs +++ b/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Runtime.InteropServices; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/JournalMap.cs b/src/LibHac/FsSystem/Save/JournalMap.cs index c03dae94..dd13c552 100644 --- a/src/LibHac/FsSystem/Save/JournalMap.cs +++ b/src/LibHac/FsSystem/Save/JournalMap.cs @@ -1,4 +1,5 @@ using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/JournalStorage.cs b/src/LibHac/FsSystem/Save/JournalStorage.cs index 05f162d0..5897b145 100644 --- a/src/LibHac/FsSystem/Save/JournalStorage.cs +++ b/src/LibHac/FsSystem/Save/JournalStorage.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/RemapStorage.cs b/src/LibHac/FsSystem/Save/RemapStorage.cs index 74fee6e4..a392a63d 100644 --- a/src/LibHac/FsSystem/Save/RemapStorage.cs +++ b/src/LibHac/FsSystem/Save/RemapStorage.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/SaveDataDirectory.cs b/src/LibHac/FsSystem/Save/SaveDataDirectory.cs index 7062a58e..a1a4e061 100644 --- a/src/LibHac/FsSystem/Save/SaveDataDirectory.cs +++ b/src/LibHac/FsSystem/Save/SaveDataDirectory.cs @@ -1,6 +1,7 @@ using System; using System.Text; using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs index b2874841..1e62ed3b 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs b/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs index c0929ec3..731676ab 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/SaveFsList.cs b/src/LibHac/FsSystem/Save/SaveFsList.cs index 47806a1a..2d83c572 100644 --- a/src/LibHac/FsSystem/Save/SaveFsList.cs +++ b/src/LibHac/FsSystem/Save/SaveFsList.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/FsSystem/Save/SaveResults.cs b/src/LibHac/FsSystem/Save/SaveResults.cs index 0ec59399..c8bfdc9a 100644 --- a/src/LibHac/FsSystem/Save/SaveResults.cs +++ b/src/LibHac/FsSystem/Save/SaveResults.cs @@ -1,4 +1,6 @@ -namespace LibHac.FsSystem.Save +using LibHac.Fs; + +namespace LibHac.FsSystem.Save { internal static class SaveResults { diff --git a/src/LibHac/FsSystem/SaveDataCreateInfo.cs b/src/LibHac/FsSystem/SaveDataCreateInfo.cs deleted file mode 100644 index 875bb0e2..00000000 --- a/src/LibHac/FsSystem/SaveDataCreateInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Runtime.InteropServices; - -namespace LibHac.FsSystem -{ - [StructLayout(LayoutKind.Explicit, Size = 0x40)] - public struct SaveDataCreateInfo - { - // Todo - } -} diff --git a/src/LibHac/FsSystem/SaveMetaCreateInfo.cs b/src/LibHac/FsSystem/SaveMetaCreateInfo.cs deleted file mode 100644 index a8677328..00000000 --- a/src/LibHac/FsSystem/SaveMetaCreateInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Runtime.InteropServices; - -namespace LibHac.FsSystem -{ - [StructLayout(LayoutKind.Explicit, Size = 0x10)] - public struct SaveMetaCreateInfo - { - [FieldOffset(0)] public int Size; - [FieldOffset(4)] public SaveMetaType Type; - } -} diff --git a/src/LibHac/FsSystem/SectorStorage.cs b/src/LibHac/FsSystem/SectorStorage.cs index 6246ed9f..1760ad3f 100644 --- a/src/LibHac/FsSystem/SectorStorage.cs +++ b/src/LibHac/FsSystem/SectorStorage.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/StorageBase.cs b/src/LibHac/FsSystem/StorageBase.cs index 0fada5e8..267bb83c 100644 --- a/src/LibHac/FsSystem/StorageBase.cs +++ b/src/LibHac/FsSystem/StorageBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/StorageExtensions.cs b/src/LibHac/FsSystem/StorageExtensions.cs index 46ee10e3..3deebdf5 100644 --- a/src/LibHac/FsSystem/StorageExtensions.cs +++ b/src/LibHac/FsSystem/StorageExtensions.cs @@ -2,6 +2,7 @@ using System.Buffers; using System.IO; using System.Runtime.InteropServices; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/StorageFile.cs b/src/LibHac/FsSystem/StorageFile.cs index 32009c5f..08f460ce 100644 --- a/src/LibHac/FsSystem/StorageFile.cs +++ b/src/LibHac/FsSystem/StorageFile.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/StorageStream.cs b/src/LibHac/FsSystem/StorageStream.cs index 265e1edf..0f900f70 100644 --- a/src/LibHac/FsSystem/StorageStream.cs +++ b/src/LibHac/FsSystem/StorageStream.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/StreamFile.cs b/src/LibHac/FsSystem/StreamFile.cs index 2103166c..c2308049 100644 --- a/src/LibHac/FsSystem/StreamFile.cs +++ b/src/LibHac/FsSystem/StreamFile.cs @@ -1,6 +1,6 @@ using System; using System.IO; - +using LibHac.Fs; #if !STREAM_SPAN using System.Buffers; #endif diff --git a/src/LibHac/FsSystem/SubStorage.cs b/src/LibHac/FsSystem/SubStorage.cs index 82616040..c8272bd8 100644 --- a/src/LibHac/FsSystem/SubStorage.cs +++ b/src/LibHac/FsSystem/SubStorage.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs index 9c2df12f..ad61357e 100644 --- a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs +++ b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Fs; namespace LibHac.FsSystem { diff --git a/src/LibHac/Kip.cs b/src/LibHac/Kip.cs index ac0e6b20..839bc544 100644 --- a/src/LibHac/Kip.cs +++ b/src/LibHac/Kip.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; using LibHac.FsSystem; namespace LibHac diff --git a/src/LibHac/Ncm/IContentStorage.cs b/src/LibHac/Ncm/IContentStorage.cs index 9834f3a0..2cd17ea9 100644 --- a/src/LibHac/Ncm/IContentStorage.cs +++ b/src/LibHac/Ncm/IContentStorage.cs @@ -1,5 +1,5 @@ using System; -using LibHac.FsSystem; +using LibHac.Fs; namespace LibHac.Ncm { diff --git a/src/LibHac/Nro.cs b/src/LibHac/Nro.cs index 1afd9710..d5cca492 100644 --- a/src/LibHac/Nro.cs +++ b/src/LibHac/Nro.cs @@ -1,4 +1,5 @@ using System.IO; +using LibHac.Fs; using LibHac.FsSystem; namespace LibHac diff --git a/src/LibHac/Nso.cs b/src/LibHac/Nso.cs index 09e49b96..59dfa245 100644 --- a/src/LibHac/Nso.cs +++ b/src/LibHac/Nso.cs @@ -1,5 +1,6 @@ using System.Collections; using System.IO; +using LibHac.Fs; using LibHac.FsSystem; namespace LibHac diff --git a/src/LibHac/Package1.cs b/src/LibHac/Package1.cs index b94f7f8e..f8dc9947 100644 --- a/src/LibHac/Package1.cs +++ b/src/LibHac/Package1.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; using LibHac.FsSystem; namespace LibHac diff --git a/src/LibHac/Package2.cs b/src/LibHac/Package2.cs index dee1e26c..9e9cf4c6 100644 --- a/src/LibHac/Package2.cs +++ b/src/LibHac/Package2.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; using LibHac.FsSystem; namespace LibHac diff --git a/src/LibHac/SwitchFs.cs b/src/LibHac/SwitchFs.cs index d6455293..f39f369c 100644 --- a/src/LibHac/SwitchFs.cs +++ b/src/LibHac/SwitchFs.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.NcaUtils; using LibHac.FsSystem.Save; diff --git a/src/LibHac/Xci.cs b/src/LibHac/Xci.cs index 4154f43f..b8250571 100644 --- a/src/LibHac/Xci.cs +++ b/src/LibHac/Xci.cs @@ -1,4 +1,5 @@ -using LibHac.FsSystem; +using LibHac.Fs; +using LibHac.FsSystem; namespace LibHac { diff --git a/src/hactoolnet/ProcessBench.cs b/src/hactoolnet/ProcessBench.cs index 1f889940..e464c39d 100644 --- a/src/hactoolnet/ProcessBench.cs +++ b/src/hactoolnet/ProcessBench.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using LibHac; +using LibHac.Fs; using LibHac.FsSystem; namespace hactoolnet diff --git a/src/hactoolnet/ProcessDelta.cs b/src/hactoolnet/ProcessDelta.cs index 3ab22e4b..3f80126b 100644 --- a/src/hactoolnet/ProcessDelta.cs +++ b/src/hactoolnet/ProcessDelta.cs @@ -2,6 +2,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Text; +using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.NcaUtils; using static hactoolnet.Print; diff --git a/src/hactoolnet/ProcessFsBuild.cs b/src/hactoolnet/ProcessFsBuild.cs index b9162cde..3f56759a 100644 --- a/src/hactoolnet/ProcessFsBuild.cs +++ b/src/hactoolnet/ProcessFsBuild.cs @@ -1,4 +1,5 @@ using System.IO; +using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.RomFs; diff --git a/src/hactoolnet/ProcessPfs.cs b/src/hactoolnet/ProcessPfs.cs index c450f7ed..fd7bbf2b 100644 --- a/src/hactoolnet/ProcessPfs.cs +++ b/src/hactoolnet/ProcessPfs.cs @@ -2,6 +2,7 @@ using System.Reflection; using System.Text; using LibHac; +using LibHac.Fs; using LibHac.FsSystem; using static hactoolnet.Print; diff --git a/src/hactoolnet/ProcessRomfs.cs b/src/hactoolnet/ProcessRomfs.cs index 86af0c46..093816ee 100644 --- a/src/hactoolnet/ProcessRomfs.cs +++ b/src/hactoolnet/ProcessRomfs.cs @@ -1,4 +1,5 @@ using System.IO; +using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.RomFs; diff --git a/src/hactoolnet/ProcessSwitchFs.cs b/src/hactoolnet/ProcessSwitchFs.cs index 441346f8..a2fa567d 100644 --- a/src/hactoolnet/ProcessSwitchFs.cs +++ b/src/hactoolnet/ProcessSwitchFs.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Text; using LibHac; +using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.NcaUtils; using LibHac.FsSystem.Save; diff --git a/src/hactoolnet/ProcessXci.cs b/src/hactoolnet/ProcessXci.cs index 240830b4..03841cca 100644 --- a/src/hactoolnet/ProcessXci.cs +++ b/src/hactoolnet/ProcessXci.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Text; using LibHac; +using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.NcaUtils; using static hactoolnet.Print; From 22940f20e5fbf9a959e7b19bd5f76f4d65e221f4 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 21 Sep 2019 13:59:35 -0500 Subject: [PATCH 24/46] Move custom storage client code together --- src/LibHac/Fs/CustomStorage.cs | 34 +++++++++++++++++++++ src/LibHac/Fs/FileSystemClient.Mount.cs | 21 ------------- src/LibHac/FsService/FileSystemProxyCore.cs | 4 +-- src/LibHac/FsService/Util.cs | 15 +-------- 4 files changed, 37 insertions(+), 37 deletions(-) create mode 100644 src/LibHac/Fs/CustomStorage.cs delete mode 100644 src/LibHac/Fs/FileSystemClient.Mount.cs diff --git a/src/LibHac/Fs/CustomStorage.cs b/src/LibHac/Fs/CustomStorage.cs new file mode 100644 index 00000000..b1081b37 --- /dev/null +++ b/src/LibHac/Fs/CustomStorage.cs @@ -0,0 +1,34 @@ +using System; +using LibHac.Common; +using LibHac.FsService; + +namespace LibHac.Fs +{ + public static class CustomStorage + { + public static Result MountCustomStorage(this FileSystemClient fs, U8Span mountName, CustomStorageId storageId) + { + Result rc = MountHelpers.CheckMountName(mountName); + if (rc.IsFailure()) return rc; + + FileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + rc = fsProxy.OpenCustomStorageFileSystem(out IFileSystem customFs, storageId); + if (rc.IsFailure()) return rc; + + return fs.Register(mountName, customFs); + } + + public static string GetCustomStorageDirectoryName(CustomStorageId storageId) + { + switch (storageId) + { + case CustomStorageId.User: + case CustomStorageId.SdCard: + return "CustomStorage0"; + default: + throw new ArgumentOutOfRangeException(nameof(storageId), storageId, null); + } + } + } +} diff --git a/src/LibHac/Fs/FileSystemClient.Mount.cs b/src/LibHac/Fs/FileSystemClient.Mount.cs deleted file mode 100644 index 4eed577d..00000000 --- a/src/LibHac/Fs/FileSystemClient.Mount.cs +++ /dev/null @@ -1,21 +0,0 @@ -using LibHac.Common; -using LibHac.FsService; - -namespace LibHac.Fs -{ - public partial class FileSystemClient - { - public Result MountCustomStorage(U8Span mountName, CustomStorageId storageId) - { - Result rc = MountHelpers.CheckMountName(mountName); - if (rc.IsFailure()) return rc; - - FileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); - - rc = fsProxy.OpenCustomStorageFileSystem(out IFileSystem customFs, storageId); - if (rc.IsFailure()) return rc; - - return FsManager.Register(mountName, customFs); - } - } -} diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 3534074d..7f30413f 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -87,7 +87,7 @@ namespace LibHac.FsService Result rc = FsCreators.SdFileSystemCreator.Create(out IFileSystem sdFs); if (rc.IsFailure()) return rc; - string customStorageDir = Util.GetCustomStorageDirectoryName(CustomStorageId.SdCard); + string customStorageDir = CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.SdCard); string subDirName = $"/{NintendoDirectoryName}/{customStorageDir}"; rc = Util.CreateSubFileSystem(out IFileSystem subFs, sdFs, subDirName, true); @@ -106,7 +106,7 @@ namespace LibHac.FsService BisPartitionId.User); if (rc.IsFailure()) return rc; - string customStorageDir = Util.GetCustomStorageDirectoryName(CustomStorageId.User); + string customStorageDir = CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.User); string subDirName = $"/{customStorageDir}"; rc = Util.CreateSubFileSystem(out IFileSystem subFs, userFs, subDirName, true); diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs index 195549e8..d41e462b 100644 --- a/src/LibHac/FsService/Util.cs +++ b/src/LibHac/FsService/Util.cs @@ -1,5 +1,4 @@ -using System; -using LibHac.Fs; +using LibHac.Fs; using LibHac.FsSystem; namespace LibHac.FsService @@ -50,17 +49,5 @@ namespace LibHac.FsService spaceId == SaveDataSpaceId.ProperSystem || spaceId == SaveDataSpaceId.Safe; } - - public static string GetCustomStorageDirectoryName(CustomStorageId storageId) - { - switch (storageId) - { - case CustomStorageId.User: - case CustomStorageId.SdCard: - return "CustomStorage0"; - default: - throw new ArgumentOutOfRangeException(nameof(storageId), storageId, null); - } - } } } From 6a449b7da18afc6abea26f2ad3be75a5eb1139be Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 21 Sep 2019 23:38:47 -0500 Subject: [PATCH 25/46] Remove IFile.Mode and create a new FileBase class --- src/LibHac/Fs/Accessors/FileAccessor.cs | 5 - src/LibHac/Fs/FileBase2.cs | 131 ++++++++++++++++++ src/LibHac/Fs/FileSystemClient.File.cs | 1 - src/LibHac/Fs/FileSystemClient.FileSystem.cs | 2 - src/LibHac/Fs/FsEnums.cs | 29 +++- src/LibHac/Fs/IFile.cs | 6 - .../Creators/ISaveDataFileSystemCreator.cs | 1 - src/LibHac/FsSystem/DirectorySaveDataFile.cs | 30 ++-- .../FsSystem/DirectorySaveDataFileSystem.cs | 2 +- src/LibHac/FsSystem/FileBase.cs | 25 ---- src/LibHac/FsSystem/FileSystemExtensions.cs | 2 +- src/LibHac/FsSystem/LocalFile.cs | 36 +++-- src/LibHac/FsSystem/NxFileStream.cs | 10 +- src/LibHac/FsSystem/Save/SaveDataFile.cs | 1 + src/LibHac/Result.cs | 7 + 15 files changed, 211 insertions(+), 77 deletions(-) create mode 100644 src/LibHac/Fs/FileBase2.cs diff --git a/src/LibHac/Fs/Accessors/FileAccessor.cs b/src/LibHac/Fs/Accessors/FileAccessor.cs index d6ef410f..da052d71 100644 --- a/src/LibHac/Fs/Accessors/FileAccessor.cs +++ b/src/LibHac/Fs/Accessors/FileAccessor.cs @@ -1,5 +1,4 @@ using System; -using LibHac.FsSystem; namespace LibHac.Fs.Accessors { @@ -11,10 +10,6 @@ namespace LibHac.Fs.Accessors public WriteState WriteState { get; private set; } public OpenMode OpenMode { get; } - // Todo: Consider removing Mode from interface because OpenMode is in FileAccessor - // Todo: Set WriteState to Error based on returned results - OpenMode IFile.Mode => OpenMode; - public FileAccessor(IFile baseFile, FileSystemAccessor parent, OpenMode mode) { File = baseFile; diff --git a/src/LibHac/Fs/FileBase2.cs b/src/LibHac/Fs/FileBase2.cs new file mode 100644 index 00000000..07cfed1a --- /dev/null +++ b/src/LibHac/Fs/FileBase2.cs @@ -0,0 +1,131 @@ +using System; +using System.Threading; + +namespace LibHac.Fs +{ + public abstract class FileBase2 : IFile + { + // 0 = not disposed; 1 = disposed + private int _disposedState; + private bool IsDisposed => _disposedState != 0; + + public abstract Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options); + public abstract Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options); + public abstract Result FlushImpl(); + public abstract Result GetSizeImpl(out long size); + public abstract Result SetSizeImpl(long size); + + public Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + { + bytesRead = default; + + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + if (destination.Length == 0) return Result.Success; + if (offset < 0) return ResultFs.ValueOutOfRange.Log(); + + return ReadImpl(out bytesRead, offset, destination, options); + } + + public Result Write(long offset, ReadOnlySpan source, WriteOption options) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + if (source.Length == 0) + { + if (options.HasFlag(WriteOption.Flush)) + { + return Flush(); + } + + return Result.Success; + } + + if (offset < 0) return ResultFs.ValueOutOfRange.Log(); + + return WriteImpl(offset, source, options); + } + + public Result Flush() + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return FlushImpl(); + } + + public Result GetSize(out long size) + { + size = 0; + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return GetSizeImpl(out size); + } + + public Result SetSize(long size) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + if (size < 0) return ResultFs.ValueOutOfRange.Log(); + + return SetSizeImpl(size); + } + + public void Dispose() + { + // Make sure Dispose is only called once + if (Interlocked.CompareExchange(ref _disposedState, 1, 0) == 0) + { + Dispose(true); + GC.SuppressFinalize(this); + } + } + + protected virtual void Dispose(bool disposing) { } + + protected Result ValidateReadParams(out long bytesToRead, long offset, int size, OpenMode openMode) + { + bytesToRead = default; + + if (!openMode.HasFlag(OpenMode.Read)) + { + return ResultFs.InvalidOpenModeForRead.Log(); + } + + Result rc = GetSize(out long fileSize); + if (rc.IsFailure()) return rc; + + if (offset > fileSize) + { + return ResultFs.ValueOutOfRange.Log(); + } + + bytesToRead = Math.Min(fileSize - offset, size); + + return Result.Success; + } + + protected Result ValidateWriteParams(long offset, int size, OpenMode openMode, out bool isResizeNeeded) + { + isResizeNeeded = false; + + if (!openMode.HasFlag(OpenMode.Write)) + { + return ResultFs.InvalidOpenModeForWrite.Log(); + } + + Result rc = GetSize(out long fileSize); + if (rc.IsFailure()) return rc; + + if (offset + size > fileSize) + { + isResizeNeeded = true; + + if (!openMode.HasFlag(OpenMode.AllowAppend)) + { + return ResultFs.AllowAppendRequiredForImplicitExtension.Log(); + } + } + + return Result.Success; + } + } +} diff --git a/src/LibHac/Fs/FileSystemClient.File.cs b/src/LibHac/Fs/FileSystemClient.File.cs index 82ae189b..fa4bbbc0 100644 --- a/src/LibHac/Fs/FileSystemClient.File.cs +++ b/src/LibHac/Fs/FileSystemClient.File.cs @@ -1,5 +1,4 @@ using System; -using LibHac.FsSystem; namespace LibHac.Fs { diff --git a/src/LibHac/Fs/FileSystemClient.FileSystem.cs b/src/LibHac/Fs/FileSystemClient.FileSystem.cs index e701a656..2f5707f1 100644 --- a/src/LibHac/Fs/FileSystemClient.FileSystem.cs +++ b/src/LibHac/Fs/FileSystemClient.FileSystem.cs @@ -1,5 +1,3 @@ -using LibHac.FsSystem; - namespace LibHac.Fs { public partial class FileSystemClient diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs index 223f36fb..08758ff7 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -1,4 +1,6 @@ -namespace LibHac.Fs +using System; + +namespace LibHac.Fs { public enum BisPartitionId { @@ -92,4 +94,29 @@ Nand = 0, SdCard = 1 } + + /// + /// Specifies which operations are available on an . + /// + [Flags] + public enum OpenMode + { + Read = 1, + Write = 2, + AllowAppend = 4, + ReadWrite = Read | Write + } + + [Flags] + public enum ReadOption + { + None = 0 + } + + [Flags] + public enum WriteOption + { + None = 0, + Flush = 1 + } } diff --git a/src/LibHac/Fs/IFile.cs b/src/LibHac/Fs/IFile.cs index bec15141..1c98e082 100644 --- a/src/LibHac/Fs/IFile.cs +++ b/src/LibHac/Fs/IFile.cs @@ -1,5 +1,4 @@ using System; -using LibHac.FsSystem; namespace LibHac.Fs { @@ -19,11 +18,6 @@ namespace LibHac.Fs /// the file will be expanded so that it is large enough to contain the written data. public interface IFile : IDisposable { - /// - /// The permissions mode for the current file. - /// - OpenMode Mode { get; } - /// /// Reads a sequence of bytes from the current . /// diff --git a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs index 29f45fb5..dd62d5ee 100644 --- a/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISaveDataFileSystemCreator.cs @@ -1,7 +1,6 @@ using System; using LibHac.Common; using LibHac.Fs; -using LibHac.FsSystem; using LibHac.FsSystem.Save; namespace LibHac.FsService.Creators diff --git a/src/LibHac/FsSystem/DirectorySaveDataFile.cs b/src/LibHac/FsSystem/DirectorySaveDataFile.cs index 09c61ba9..1a420ae3 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFile.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFile.cs @@ -3,57 +3,49 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class DirectorySaveDataFile : FileBase + public class DirectorySaveDataFile : FileBase2 { private IFile BaseFile { get; } private DirectorySaveDataFileSystem ParentFs { get; } - private object DisposeLocker { get; } = new object(); + private OpenMode Mode { get; } - public DirectorySaveDataFile(DirectorySaveDataFileSystem parentFs, IFile baseFile) + public DirectorySaveDataFile(DirectorySaveDataFileSystem parentFs, IFile baseFile, OpenMode mode) { ParentFs = parentFs; BaseFile = baseFile; - Mode = BaseFile.Mode; - ToDispose.Add(BaseFile); + Mode = mode; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { return BaseFile.Read(out bytesRead, offset, destination, options); } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { return BaseFile.Write(offset, source, options); } - public override Result Flush() + public override Result FlushImpl() { return BaseFile.Flush(); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { return BaseFile.GetSize(out size); } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { return BaseFile.SetSize(size); } protected override void Dispose(bool disposing) { - lock (DisposeLocker) + if (Mode.HasFlag(OpenMode.Write)) { - if (IsDisposed) return; - - base.Dispose(disposing); - - if (Mode.HasFlag(OpenMode.Write)) - { - ParentFs.NotifyCloseWritableFile(); - } + ParentFs.NotifyCloseWritableFile(); } } } diff --git a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs index cfa98fbe..361f6ce7 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs @@ -114,7 +114,7 @@ namespace LibHac.FsSystem Result rc = BaseFs.OpenFile(out IFile baseFile, fullPath, mode); if (rc.IsFailure()) return rc; - file = new DirectorySaveDataFile(this, baseFile); + file = new DirectorySaveDataFile(this, baseFile, mode); if (mode.HasFlag(OpenMode.Write)) { diff --git a/src/LibHac/FsSystem/FileBase.cs b/src/LibHac/FsSystem/FileBase.cs index 33b30489..4079ca85 100644 --- a/src/LibHac/FsSystem/FileBase.cs +++ b/src/LibHac/FsSystem/FileBase.cs @@ -83,29 +83,4 @@ namespace LibHac.FsSystem IsDisposed = true; } } - - /// - /// Specifies which operations are available on an . - /// - [Flags] - public enum OpenMode - { - Read = 1, - Write = 2, - AllowAppend = 4, - ReadWrite = Read | Write - } - - [Flags] - public enum ReadOption - { - None = 0 - } - - [Flags] - public enum WriteOption - { - None = 0, - Flush = 1 - } } diff --git a/src/LibHac/FsSystem/FileSystemExtensions.cs b/src/LibHac/FsSystem/FileSystemExtensions.cs index fd7ba09b..1c89dd2c 100644 --- a/src/LibHac/FsSystem/FileSystemExtensions.cs +++ b/src/LibHac/FsSystem/FileSystemExtensions.cs @@ -152,7 +152,7 @@ namespace LibHac.FsSystem public static IStorage AsStorage(this IFile file) => new FileStorage(file); public static Stream AsStream(this IFile file) => new NxFileStream(file, true); - public static Stream AsStream(this IFile file, bool keepOpen) => new NxFileStream(file, keepOpen); + public static Stream AsStream(this IFile file, OpenMode mode, bool keepOpen) => new NxFileStream(file, mode, keepOpen); public static IFile AsIFile(this Stream stream, OpenMode mode) => new StreamFile(stream, mode); diff --git a/src/LibHac/FsSystem/LocalFile.cs b/src/LibHac/FsSystem/LocalFile.cs index 92fc844b..370de75d 100644 --- a/src/LibHac/FsSystem/LocalFile.cs +++ b/src/LibHac/FsSystem/LocalFile.cs @@ -4,49 +4,51 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class LocalFile : FileBase + public class LocalFile : FileBase2 { private const int ErrorHandleDiskFull = unchecked((int)0x80070027); private const int ErrorDiskFull = unchecked((int)0x80070070); private FileStream Stream { get; } private StreamFile File { get; } + private OpenMode Mode { get; } public LocalFile(string path, OpenMode mode) { Mode = mode; Stream = OpenFile(path, mode); File = new StreamFile(Stream, mode); - - ToDispose.Add(File); - ToDispose.Add(Stream); } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { - int toRead = ValidateReadParamsAndGetSize(destination, offset); + bytesRead = 0; - return File.Read(out bytesRead, offset, destination.Slice(0, toRead), options); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; + + return File.Read(out bytesRead, offset, destination.Slice(0, (int)toRead), options); } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out _); + if (rc.IsFailure()) return rc; return File.Write(offset, source, options); } - public override Result Flush() + public override Result FlushImpl() { return File.Flush(); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { return File.GetSize(out size); } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { try { @@ -60,6 +62,16 @@ namespace LibHac.FsSystem return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + File?.Dispose(); + } + + Stream?.Dispose(); + } + private static FileAccess GetFileAccess(OpenMode mode) { // FileAccess and OpenMode have the same flags diff --git a/src/LibHac/FsSystem/NxFileStream.cs b/src/LibHac/FsSystem/NxFileStream.cs index 48b5d99f..00d8593e 100644 --- a/src/LibHac/FsSystem/NxFileStream.cs +++ b/src/LibHac/FsSystem/NxFileStream.cs @@ -8,11 +8,15 @@ namespace LibHac.FsSystem { private IFile BaseFile { get; } private bool LeaveOpen { get; } + private OpenMode Mode { get; } private long _length; - public NxFileStream(IFile baseFile, bool leaveOpen) + public NxFileStream(IFile baseFile, bool leaveOpen) : this(baseFile, OpenMode.ReadWrite, leaveOpen) { } + + public NxFileStream(IFile baseFile, OpenMode mode, bool leaveOpen) { BaseFile = baseFile; + Mode = mode; LeaveOpen = leaveOpen; baseFile.GetSize(out _length).ThrowIfFailure(); @@ -63,9 +67,9 @@ namespace LibHac.FsSystem BaseFile.GetSize(out _length).ThrowIfFailure(); } - public override bool CanRead => BaseFile.Mode.HasFlag(OpenMode.Read); + public override bool CanRead => Mode.HasFlag(OpenMode.Read); public override bool CanSeek => true; - public override bool CanWrite => BaseFile.Mode.HasFlag(OpenMode.Write); + public override bool CanWrite => Mode.HasFlag(OpenMode.Write); public override long Length => _length; public override long Position { get; set; } diff --git a/src/LibHac/FsSystem/Save/SaveDataFile.cs b/src/LibHac/FsSystem/Save/SaveDataFile.cs index 8dc2f3d8..56a56ec5 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFile.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFile.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem.Save { diff --git a/src/LibHac/Result.cs b/src/LibHac/Result.cs index 86e90ba1..33c2875d 100644 --- a/src/LibHac/Result.cs +++ b/src/LibHac/Result.cs @@ -1,8 +1,10 @@ using System; +using System.Diagnostics; namespace LibHac { [Serializable] + [DebuggerDisplay("{ToString()}")] public struct Result : IEquatable { public readonly int Value; @@ -43,6 +45,11 @@ namespace LibHac return this; } + public override string ToString() + { + return IsSuccess() ? "Success" : ErrorCode; + } + public override bool Equals(object obj) { return obj is Result result && Equals(result); From fd40b2fd77f56c698b9833f4cd4275a0fdf6336f Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 23 Sep 2019 00:36:47 -0500 Subject: [PATCH 26/46] Remove the old FileBase class --- src/LibHac/Fs/{FileBase2.cs => FileBase.cs} | 2 +- src/LibHac/FsService/Permissions.cs | 2 +- src/LibHac/FsSystem/AesXtsFile.cs | 35 ++++++-- src/LibHac/FsSystem/AesXtsFileSystem.cs | 2 - src/LibHac/FsSystem/ConcatenationFile.cs | 41 +++++++--- src/LibHac/FsSystem/DirectorySaveDataFile.cs | 2 +- src/LibHac/FsSystem/FileBase.cs | 86 -------------------- src/LibHac/FsSystem/LocalFile.cs | 2 +- src/LibHac/FsSystem/NullFile.cs | 20 +++-- src/LibHac/FsSystem/PartitionFile.cs | 39 ++++++--- src/LibHac/FsSystem/ReadOnlyFile.cs | 14 ++-- src/LibHac/FsSystem/RomFs/RomFsFile.cs | 16 ++-- src/LibHac/FsSystem/Save/SaveDataFile.cs | 31 +++++-- src/LibHac/FsSystem/StorageFile.cs | 44 +++++++--- src/LibHac/FsSystem/StreamFile.cs | 30 ++++--- 15 files changed, 188 insertions(+), 178 deletions(-) rename src/LibHac/Fs/{FileBase2.cs => FileBase.cs} (98%) delete mode 100644 src/LibHac/FsSystem/FileBase.cs diff --git a/src/LibHac/Fs/FileBase2.cs b/src/LibHac/Fs/FileBase.cs similarity index 98% rename from src/LibHac/Fs/FileBase2.cs rename to src/LibHac/Fs/FileBase.cs index 07cfed1a..5caa7829 100644 --- a/src/LibHac/Fs/FileBase2.cs +++ b/src/LibHac/Fs/FileBase.cs @@ -3,7 +3,7 @@ using System.Threading; namespace LibHac.Fs { - public abstract class FileBase2 : IFile + public abstract class FileBase : IFile { // 0 = not disposed; 1 = disposed private int _disposedState; diff --git a/src/LibHac/FsService/Permissions.cs b/src/LibHac/FsService/Permissions.cs index aa773235..2163df8b 100644 --- a/src/LibHac/FsService/Permissions.cs +++ b/src/LibHac/FsService/Permissions.cs @@ -3,7 +3,7 @@ namespace LibHac.FsService { /// - /// Permissions that control which storages or filesystems can be mounted or opened. + /// Permissions that control which filesystems or storages can be mounted or opened. /// public enum AccessPermissions { diff --git a/src/LibHac/FsSystem/AesXtsFile.cs b/src/LibHac/FsSystem/AesXtsFile.cs index bd70578f..00fb3403 100644 --- a/src/LibHac/FsSystem/AesXtsFile.cs +++ b/src/LibHac/FsSystem/AesXtsFile.cs @@ -10,6 +10,7 @@ namespace LibHac.FsSystem private byte[] KekSeed { get; } private byte[] VerificationKey { get; } private int BlockSize { get; } + private OpenMode Mode { get; } private AesXtsFileHeader Header { get; } private IStorage BaseStorage { get; } @@ -52,23 +53,31 @@ namespace LibHac.FsSystem return key; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; - int toRead = ValidateReadParamsAndGetSize(destination, offset); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; - Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead)); if (rc.IsFailure()) return rc; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); + if (rc.IsFailure()) return rc; - Result rc = BaseStorage.Write(offset, source); + if (isResizeNeeded) + { + rc = SetSizeImpl(offset + source.Length); + if (rc.IsFailure()) return rc; + } + + rc = BaseStorage.Write(offset, source); if (rc.IsFailure()) return rc; if ((options & WriteOption.Flush) != 0) @@ -79,18 +88,18 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Header.Size; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { Header.SetSize(size, VerificationKey); @@ -99,5 +108,13 @@ namespace LibHac.FsSystem return BaseStorage.SetSize(size); } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + BaseFile?.Dispose(); + } + } } } diff --git a/src/LibHac/FsSystem/AesXtsFileSystem.cs b/src/LibHac/FsSystem/AesXtsFileSystem.cs index a5de6e98..ccfca772 100644 --- a/src/LibHac/FsSystem/AesXtsFileSystem.cs +++ b/src/LibHac/FsSystem/AesXtsFileSystem.cs @@ -107,8 +107,6 @@ namespace LibHac.FsSystem var xtsFile = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize); - xtsFile.ToDispose.Add(baseFile); - file = xtsFile; return Result.Success; } diff --git a/src/LibHac/FsSystem/ConcatenationFile.cs b/src/LibHac/FsSystem/ConcatenationFile.cs index 88ee7589..81f2598d 100644 --- a/src/LibHac/FsSystem/ConcatenationFile.cs +++ b/src/LibHac/FsSystem/ConcatenationFile.cs @@ -12,6 +12,7 @@ namespace LibHac.FsSystem private string FilePath { get; } private List Sources { get; } private long SubFileSize { get; } + private OpenMode Mode { get; } internal ConcatenationFile(IFileSystem baseFileSystem, string path, IEnumerable sources, long subFileSize, OpenMode mode) { @@ -30,17 +31,17 @@ namespace LibHac.FsSystem throw new ArgumentException($"Source file must have size {subFileSize}"); } } - - ToDispose.AddRange(Sources); } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; long inPos = offset; int outPos = 0; - int remaining = ValidateReadParamsAndGetSize(destination, offset); + + Result rc = ValidateReadParams(out long remaining, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; GetSize(out long fileSize).ThrowIfFailure(); @@ -53,12 +54,12 @@ namespace LibHac.FsSystem long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); int bytesToRead = (int)Math.Min(fileEndOffset - inPos, remaining); - Result rc = file.Read(out long subFileBytesRead, fileOffset, destination.Slice(outPos, bytesToRead), options); + rc = file.Read(out long subFileBytesRead, fileOffset, destination.Slice(outPos, bytesToRead), options); if (rc.IsFailure()) return rc; outPos += (int)subFileBytesRead; inPos += subFileBytesRead; - remaining -= (int)subFileBytesRead; + remaining -= subFileBytesRead; if (bytesRead < bytesToRead) break; } @@ -68,9 +69,10 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out _); + if (rc.IsFailure()) return rc; int inPos = 0; long outPos = offset; @@ -87,7 +89,7 @@ namespace LibHac.FsSystem long fileEndOffset = Math.Min((fileIndex + 1) * SubFileSize, fileSize); int bytesToWrite = (int)Math.Min(fileEndOffset - outPos, remaining); - Result rc = file.Write(fileOffset, source.Slice(inPos, bytesToWrite), options); + rc = file.Write(fileOffset, source.Slice(inPos, bytesToWrite), options); if (rc.IsFailure()) return rc; outPos += bytesToWrite; @@ -95,7 +97,7 @@ namespace LibHac.FsSystem remaining -= bytesToWrite; } - if ((options & WriteOption.Flush) != 0) + if (options.HasFlag(WriteOption.Flush)) { return Flush(); } @@ -103,7 +105,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { foreach (IFile file in Sources) { @@ -114,7 +116,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = default; @@ -129,7 +131,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { Result rc = GetSize(out long currentSize); if (rc.IsFailure()) return rc; @@ -183,6 +185,19 @@ namespace LibHac.FsSystem return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + foreach (IFile file in Sources) + { + file?.Dispose(); + } + + Sources.Clear(); + } + } + private int GetSubFileIndexFromOffset(long offset) { return (int)(offset / SubFileSize); diff --git a/src/LibHac/FsSystem/DirectorySaveDataFile.cs b/src/LibHac/FsSystem/DirectorySaveDataFile.cs index 1a420ae3..053c4c75 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFile.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFile.cs @@ -3,7 +3,7 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class DirectorySaveDataFile : FileBase2 + public class DirectorySaveDataFile : FileBase { private IFile BaseFile { get; } private DirectorySaveDataFileSystem ParentFs { get; } diff --git a/src/LibHac/FsSystem/FileBase.cs b/src/LibHac/FsSystem/FileBase.cs deleted file mode 100644 index 4079ca85..00000000 --- a/src/LibHac/FsSystem/FileBase.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using LibHac.Fs; - -namespace LibHac.FsSystem -{ - public abstract class FileBase : IFile - { - protected bool IsDisposed { get; private set; } - internal List ToDispose { get; } = new List(); - - public abstract Result Read(out long bytesRead, long offset, Span destination, ReadOption options); - public abstract Result Write(long offset, ReadOnlySpan source, WriteOption options); - public abstract Result Flush(); - public abstract Result GetSize(out long size); - public abstract Result SetSize(long size); - - public OpenMode Mode { get; protected set; } - - protected int ValidateReadParamsAndGetSize(ReadOnlySpan span, long offset) - { - if (IsDisposed) throw new ObjectDisposedException(null); - - if ((Mode & OpenMode.Read) == 0) ThrowHelper.ThrowResult(ResultFs.InvalidOpenModeForRead, "File does not allow reading."); - if (span == null) throw new ArgumentNullException(nameof(span)); - if (offset < 0) ThrowHelper.ThrowResult(ResultFs.ValueOutOfRange, "Offset must be non-negative."); - - Result sizeResult = GetSize(out long fileSize); - sizeResult.ThrowIfFailure(); - - int size = span.Length; - - if (offset > fileSize) ThrowHelper.ThrowResult(ResultFs.ValueOutOfRange, "Offset must be less than the file size."); - - return (int)Math.Min(fileSize - offset, size); - } - - protected void ValidateWriteParams(ReadOnlySpan span, long offset) - { - if (IsDisposed) throw new ObjectDisposedException(null); - - if ((Mode & OpenMode.Write) == 0) ThrowHelper.ThrowResult(ResultFs.InvalidOpenModeForWrite, "File does not allow writing."); - - if (span == null) throw new ArgumentNullException(nameof(span)); - if (offset < 0) ThrowHelper.ThrowResult(ResultFs.ValueOutOfRange, "Offset must be non-negative."); - - Result sizeResult = GetSize(out long fileSize); - sizeResult.ThrowIfFailure(); - - int size = span.Length; - - if (offset + size > fileSize) - { - if ((Mode & OpenMode.AllowAppend) == 0) - { - ThrowHelper.ThrowResult(ResultFs.AllowAppendRequiredForImplicitExtension); - } - - SetSize(offset + size); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (IsDisposed) return; - - if (disposing) - { - Flush(); - - foreach (IDisposable item in ToDispose) - { - item?.Dispose(); - } - } - - IsDisposed = true; - } - } -} diff --git a/src/LibHac/FsSystem/LocalFile.cs b/src/LibHac/FsSystem/LocalFile.cs index 370de75d..b4f02612 100644 --- a/src/LibHac/FsSystem/LocalFile.cs +++ b/src/LibHac/FsSystem/LocalFile.cs @@ -4,7 +4,7 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class LocalFile : FileBase2 + public class LocalFile : FileBase { private const int ErrorHandleDiskFull = unchecked((int)0x80070027); private const int ErrorDiskFull = unchecked((int)0x80070070); diff --git a/src/LibHac/FsSystem/NullFile.cs b/src/LibHac/FsSystem/NullFile.cs index a3d12591..44c79721 100644 --- a/src/LibHac/FsSystem/NullFile.cs +++ b/src/LibHac/FsSystem/NullFile.cs @@ -5,6 +5,8 @@ namespace LibHac.FsSystem { public class NullFile : FileBase { + private OpenMode Mode { get; } + public NullFile() { Mode = OpenMode.ReadWrite; @@ -14,32 +16,36 @@ namespace LibHac.FsSystem private long Length { get; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { - int toRead = ValidateReadParamsAndGetSize(destination, offset); - destination.Slice(0, toRead).Clear(); + bytesRead = 0; + + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; + + destination.Slice(0, (int)toRead).Clear(); bytesRead = toRead; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { return Result.Success; } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Length; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperation.Log(); } diff --git a/src/LibHac/FsSystem/PartitionFile.cs b/src/LibHac/FsSystem/PartitionFile.cs index 0c734f13..12468d96 100644 --- a/src/LibHac/FsSystem/PartitionFile.cs +++ b/src/LibHac/FsSystem/PartitionFile.cs @@ -8,6 +8,7 @@ namespace LibHac.FsSystem private IStorage BaseStorage { get; } private long Offset { get; } private long Size { get; } + private OpenMode Mode { get; } public PartitionFile(IStorage baseStorage, long offset, long size, OpenMode mode) { @@ -17,27 +18,34 @@ namespace LibHac.FsSystem Size = size; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { - bytesRead = default; + bytesRead = 0; - int toRead = ValidateReadParamsAndGetSize(destination, offset); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; long storageOffset = Offset + offset; - BaseStorage.Read(storageOffset, destination.Slice(0, toRead)); + BaseStorage.Read(storageOffset, destination.Slice(0, (int)toRead)); bytesRead = toRead; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); - - Result rc = BaseStorage.Write(offset, source); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); if (rc.IsFailure()) return rc; - if ((options & WriteOption.Flush) != 0) + if (isResizeNeeded) return ResultFs.UnsupportedOperationInPartitionFileSetSize.Log(); + + if (offset > Size) return ResultFs.ValueOutOfRange.Log(); + + rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; + + // N doesn't flush if the flag is set + if (options.HasFlag(WriteOption.Flush)) { return BaseStorage.Flush(); } @@ -45,9 +53,9 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { - if ((Mode & OpenMode.Write) != 0) + if (!Mode.HasFlag(OpenMode.Write)) { return BaseStorage.Flush(); } @@ -55,14 +63,19 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Size; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { + if (!Mode.HasFlag(OpenMode.Write)) + { + return ResultFs.InvalidOpenModeForWrite.Log(); + } + return ResultFs.UnsupportedOperationInPartitionFileSetSize.Log(); } } diff --git a/src/LibHac/FsSystem/ReadOnlyFile.cs b/src/LibHac/FsSystem/ReadOnlyFile.cs index 07611c3f..8945f1be 100644 --- a/src/LibHac/FsSystem/ReadOnlyFile.cs +++ b/src/LibHac/FsSystem/ReadOnlyFile.cs @@ -12,29 +12,29 @@ namespace LibHac.FsSystem BaseFile = baseFile; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { return BaseFile.Read(out bytesRead, offset, destination, options); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { return BaseFile.GetSize(out size); } - public override Result Flush() + public override Result FlushImpl() { return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - return ResultFs.UnsupportedOperationModifyReadOnlyFile.Log(); + return ResultFs.InvalidOpenModeForWrite.Log(); } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { - return ResultFs.UnsupportedOperationModifyReadOnlyFile.Log(); + return ResultFs.InvalidOpenModeForWrite.Log(); } } } diff --git a/src/LibHac/FsSystem/RomFs/RomFsFile.cs b/src/LibHac/FsSystem/RomFs/RomFsFile.cs index d069d860..3f304868 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsFile.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsFile.cs @@ -11,21 +11,21 @@ namespace LibHac.FsSystem.RomFs public RomFsFile(IStorage baseStorage, long offset, long size) { - Mode = OpenMode.Read; BaseStorage = baseStorage; Offset = offset; Size = size; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; - int toRead = ValidateReadParamsAndGetSize(destination, offset); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, OpenMode.Read); + if (rc.IsFailure()) return rc; long storageOffset = Offset + offset; - Result rc = BaseStorage.Read(storageOffset, destination.Slice(0, toRead)); + rc = BaseStorage.Read(storageOffset, destination.Slice(0, (int)toRead)); if (rc.IsFailure()) return rc; bytesRead = toRead; @@ -33,23 +33,23 @@ namespace LibHac.FsSystem.RomFs return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } - public override Result Flush() + public override Result FlushImpl() { return Result.Success; } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Size; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } diff --git a/src/LibHac/FsSystem/Save/SaveDataFile.cs b/src/LibHac/FsSystem/Save/SaveDataFile.cs index 56a56ec5..93b7d07e 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFile.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFile.cs @@ -10,6 +10,7 @@ namespace LibHac.FsSystem.Save private string Path { get; } private HierarchicalSaveFileTable FileTable { get; } private long Size { get; set; } + private OpenMode Mode { get; } public SaveDataFile(AllocationTableStorage baseStorage, string path, HierarchicalSaveFileTable fileTable, long size, OpenMode mode) { @@ -20,22 +21,36 @@ namespace LibHac.FsSystem.Save Size = size; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; - int toRead = ValidateReadParamsAndGetSize(destination, offset); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; - Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + if (toRead == 0) + { + bytesRead = 0; + return Result.Success; + } + + rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead)); if (rc.IsFailure()) return rc; bytesRead = toRead; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); + if (rc.IsFailure()) return rc; + + if (isResizeNeeded) + { + rc = SetSizeImpl(offset + source.Length); + if (rc.IsFailure()) return rc; + } BaseStorage.Write(offset, source); @@ -47,18 +62,18 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = Size; return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { if (size < 0) throw new ArgumentOutOfRangeException(nameof(size)); if (Size == size) return Result.Success; diff --git a/src/LibHac/FsSystem/StorageFile.cs b/src/LibHac/FsSystem/StorageFile.cs index 08f460ce..604dfd6c 100644 --- a/src/LibHac/FsSystem/StorageFile.cs +++ b/src/LibHac/FsSystem/StorageFile.cs @@ -6,6 +6,7 @@ namespace LibHac.FsSystem public class StorageFile : FileBase { private IStorage BaseStorage { get; } + private OpenMode Mode { get; } public StorageFile(IStorage baseStorage, OpenMode mode) { @@ -13,26 +14,41 @@ namespace LibHac.FsSystem Mode = mode; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; - int toRead = ValidateReadParamsAndGetSize(destination, offset); - Result rc = BaseStorage.Read(offset, destination.Slice(0, toRead)); + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; + + if (toRead == 0) + { + bytesRead = 0; + return Result.Success; + } + + rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead)); if (rc.IsFailure()) return rc; bytesRead = toRead; return Result.Success; } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { - ValidateWriteParams(source, offset); - - Result rc = BaseStorage.Write(offset, source); + Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); if (rc.IsFailure()) return rc; - if ((options & WriteOption.Flush) != 0) + if (isResizeNeeded) + { + rc = SetSizeImpl(offset + source.Length); + if (rc.IsFailure()) return rc; + } + + rc = BaseStorage.Write(offset, source); + if (rc.IsFailure()) return rc; + + if (options.HasFlag(WriteOption.Flush)) { return Flush(); } @@ -40,18 +56,24 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { + if (!Mode.HasFlag(OpenMode.Write)) + return Result.Success; + return BaseStorage.Flush(); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { return BaseStorage.GetSize(out size); } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { + if (!Mode.HasFlag(OpenMode.Write)) + return ResultFs.InvalidOpenModeForWrite.Log(); + return BaseStorage.SetSize(size); } } diff --git a/src/LibHac/FsSystem/StreamFile.cs b/src/LibHac/FsSystem/StreamFile.cs index c2308049..90db129d 100644 --- a/src/LibHac/FsSystem/StreamFile.cs +++ b/src/LibHac/FsSystem/StreamFile.cs @@ -1,6 +1,7 @@ using System; using System.IO; using LibHac.Fs; + #if !STREAM_SPAN using System.Buffers; #endif @@ -14,6 +15,7 @@ namespace LibHac.FsSystem { // todo: handle Stream exceptions + private OpenMode Mode { get; } private Stream BaseStream { get; } private object Locker { get; } = new object(); @@ -23,8 +25,13 @@ namespace LibHac.FsSystem Mode = mode; } - public override Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { + bytesRead = default; + + Result rc = ValidateReadParams(out long toRead, offset, destination.Length, Mode); + if (rc.IsFailure()) return rc; + #if STREAM_SPAN lock (Locker) { @@ -33,11 +40,11 @@ namespace LibHac.FsSystem BaseStream.Position = offset; } - bytesRead = BaseStream.Read(destination); + bytesRead = BaseStream.Read(destination.Slice(0, (int)toRead)); return Result.Success; } #else - byte[] buffer = ArrayPool.Shared.Rent(destination.Length); + byte[] buffer = ArrayPool.Shared.Rent((int)toRead); try { lock (Locker) @@ -47,10 +54,10 @@ namespace LibHac.FsSystem BaseStream.Position = offset; } - bytesRead = BaseStream.Read(buffer, 0, destination.Length); + bytesRead = BaseStream.Read(buffer, 0, (int)toRead); } - new Span(buffer, 0, destination.Length).CopyTo(destination); + new Span(buffer, 0, (int)bytesRead).CopyTo(destination); return Result.Success; } @@ -58,8 +65,11 @@ namespace LibHac.FsSystem #endif } - public override Result Write(long offset, ReadOnlySpan source, WriteOption options) + public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { + Result rc = ValidateWriteParams(offset, source.Length, Mode, out _); + if (rc.IsFailure()) return rc; + #if STREAM_SPAN lock (Locker) { @@ -81,7 +91,7 @@ namespace LibHac.FsSystem finally { ArrayPool.Shared.Return(buffer); } #endif - if ((options & WriteOption.Flush) != 0) + if (options.HasFlag(WriteOption.Flush)) { return Flush(); } @@ -89,7 +99,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + public override Result FlushImpl() { lock (Locker) { @@ -98,7 +108,7 @@ namespace LibHac.FsSystem } } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { lock (Locker) { @@ -107,7 +117,7 @@ namespace LibHac.FsSystem } } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { lock (Locker) { From c89bc1c706ba5bb2780866e623ba2fcd3d5e58ed Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 23 Sep 2019 18:37:23 -0500 Subject: [PATCH 27/46] Make FileSystemProxy implement IFileSystemProxy --- src/LibHac/Common/StringUtils.cs | 12 + src/LibHac/Fs/ContentStorage.cs | 2 +- src/LibHac/Fs/CustomStorage.cs | 2 +- src/LibHac/Fs/FileSystemClient.cs | 4 +- src/LibHac/FsService/FileSystemProxy.cs | 537 ++++++++++++++++++++--- src/LibHac/FsService/FileSystemServer.cs | 2 +- src/LibHac/FsSystem/FsPath.cs | 1 + src/LibHac/FsSystem/PathTools.cs | 15 + 8 files changed, 499 insertions(+), 76 deletions(-) diff --git a/src/LibHac/Common/StringUtils.cs b/src/LibHac/Common/StringUtils.cs index b4501ea7..df4443c9 100644 --- a/src/LibHac/Common/StringUtils.cs +++ b/src/LibHac/Common/StringUtils.cs @@ -33,6 +33,18 @@ namespace LibHac.Common return i; } + public static int GetLength(ReadOnlySpan s, int maxLen) + { + int i = 0; + + while (i < maxLen && i < s.Length && s[i] != 0) + { + i++; + } + + return i; + } + /// /// Concatenates 2 byte strings. /// diff --git a/src/LibHac/Fs/ContentStorage.cs b/src/LibHac/Fs/ContentStorage.cs index c9545d71..c74d2763 100644 --- a/src/LibHac/Fs/ContentStorage.cs +++ b/src/LibHac/Fs/ContentStorage.cs @@ -20,7 +20,7 @@ namespace LibHac.Fs Result rc = MountHelpers.CheckMountNameAcceptingReservedMountName(mountName); if (rc.IsFailure()) return rc; - FileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); rc = fsProxy.OpenContentStorageFileSystem(out IFileSystem contentFs, storageId); if (rc.IsFailure()) return rc; diff --git a/src/LibHac/Fs/CustomStorage.cs b/src/LibHac/Fs/CustomStorage.cs index b1081b37..f97727b1 100644 --- a/src/LibHac/Fs/CustomStorage.cs +++ b/src/LibHac/Fs/CustomStorage.cs @@ -11,7 +11,7 @@ namespace LibHac.Fs Result rc = MountHelpers.CheckMountName(mountName); if (rc.IsFailure()) return rc; - FileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); rc = fsProxy.OpenCustomStorageFileSystem(out IFileSystem customFs, storageId); if (rc.IsFailure()) return rc; diff --git a/src/LibHac/Fs/FileSystemClient.cs b/src/LibHac/Fs/FileSystemClient.cs index 999aa7a6..76ce211b 100644 --- a/src/LibHac/Fs/FileSystemClient.cs +++ b/src/LibHac/Fs/FileSystemClient.cs @@ -6,7 +6,7 @@ namespace LibHac.Fs public partial class FileSystemClient { private FileSystemServer FsSrv { get; } - private FileSystemProxy FsProxy { get; set; } + private IFileSystemProxy FsProxy { get; set; } private FileSystemManager FsManager { get; } private readonly object _fspInitLocker = new object(); @@ -17,7 +17,7 @@ namespace LibHac.Fs FsManager = new FileSystemManager(timer); } - public FileSystemProxy GetFileSystemProxyServiceObject() + public IFileSystemProxy GetFileSystemProxyServiceObject() { if (FsProxy != null) return FsProxy; diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index a579ea05..cfa8c405 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -2,10 +2,12 @@ using LibHac.Common; using LibHac.Fs; using LibHac.FsSystem; +using LibHac.Ncm; +using LibHac.Spl; namespace LibHac.FsService { - public class FileSystemProxy + public class FileSystemProxy : IFileSystemProxy { private FileSystemProxyCore FsProxyCore { get; } @@ -17,7 +19,7 @@ namespace LibHac.FsService public long SaveDataSize { get; private set; } public long SaveDataJournalSize { get; private set; } - public string SaveDataRootPath { get; private set; } + public FsPath SaveDataRootPath { get; } = default; public bool AutoCreateSaveData { get; private set; } private const ulong SaveIndexerId = 0x8000000000000000; @@ -30,10 +32,19 @@ namespace LibHac.FsService CurrentProcess = -1; SaveDataSize = 0x2000000; SaveDataJournalSize = 0x1000000; - SaveDataRootPath = string.Empty; AutoCreateSaveData = true; } + public Result OpenFileSystemWithId(out IFileSystem fileSystem, ref FsPath path, TitleId titleId, FileSystemType type) + { + throw new NotImplementedException(); + } + + public Result OpenFileSystemWithPatch(out IFileSystem fileSystem, TitleId titleId, FileSystemType type) + { + throw new NotImplementedException(); + } + public Result SetCurrentProcess(long processId) { CurrentProcess = processId; @@ -41,104 +52,100 @@ namespace LibHac.FsService return Result.Success; } - public Result DisableAutoSaveDataCreation() + public Result GetFreeSpaceSizeForSaveData(out long freeSpaceSize, SaveDataSpaceId spaceId) { - AutoCreateSaveData = false; - - return Result.Success; + throw new NotImplementedException(); } - public Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize) + public Result OpenDataFileSystemByCurrentProcess(out IFileSystem fileSystem) { - if (saveDataSize < 0 || saveDataJournalSize < 0) - { - return ResultFs.InvalidSize; - } - - SaveDataSize = saveDataSize; - SaveDataJournalSize = saveDataJournalSize; - - return Result.Success; + throw new NotImplementedException(); } - public Result SetSaveDataRootPath(string path) + public Result OpenDataFileSystemByProgramId(out IFileSystem fileSystem, TitleId titleId) { - // Missing permission check - - if (path.Length > PathTools.MaxPathLength) - { - return ResultFs.TooLongPath; - } - - SaveDataRootPath = path; - - return Result.Success; + throw new NotImplementedException(); } - public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) + public Result OpenDataStorageByCurrentProcess(out IStorage storage) { - // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter - - return FsProxyCore.OpenBisFileSystem(out fileSystem, rootPath, partitionId); + throw new NotImplementedException(); } - public Result OpenSdCardFileSystem(out IFileSystem fileSystem) + public Result OpenDataStorageByProgramId(out IStorage storage, TitleId programId) { - // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter - - return FsProxyCore.OpenSdCardFileSystem(out fileSystem); + throw new NotImplementedException(); } - public Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId) + public Result OpenDataStorageByDataId(out IStorage storage, TitleId dataId, StorageId storageId) { - // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter - - return FsProxyCore.OpenContentStorageFileSystem(out fileSystem, storageId); + throw new NotImplementedException(); } - public Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId) + public Result OpenPatchDataStorageByCurrentProcess(out IStorage storage) { - // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter - - return FsProxyCore.OpenCustomStorageFileSystem(out fileSystem, storageId); + throw new NotImplementedException(); } - public Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, - SaveDataAttribute attribute) + public Result OpenDataFileSystemWithProgramIndex(out IFileSystem fileSystem, byte programIndex) { - // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter - fileSystem = default; - - if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log(); - - Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out _, spaceId, - attribute, false, true); - if (rc.IsFailure()) return rc; - - // Missing check if the current title owns the save data or can open it - - fileSystem = saveFs; - - return Result.Success; + throw new NotImplementedException(); } - public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) + public Result OpenDataStorageWithProgramIndex(out IStorage storage, byte programIndex) { - // todo: use struct instead of byte span - if (seed.Length != 0x10) return ResultFs.InvalidSize; + throw new NotImplementedException(); + } - // Missing permission check + public Result RegisterSaveDataFileSystemAtomicDeletion(ReadOnlySpan saveDataIds) + { + throw new NotImplementedException(); + } - Result rc = FsProxyCore.SetSdCardEncryptionSeed(seed); - if (rc.IsFailure()) return rc; + public Result DeleteSaveDataFileSystem(ulong saveDataId) + { + throw new NotImplementedException(); + } - // todo: Reset save data indexer + public Result DeleteSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId) + { + throw new NotImplementedException(); + } - return Result.Success; + public Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute) + { + throw new NotImplementedException(); + } + + public Result UpdateSaveDataMacForDebug(SaveDataSpaceId spaceId, ulong saveDataId) + { + throw new NotImplementedException(); + } + + public Result CreateSaveDataFileSystem(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo, + ref SaveMetaCreateInfo metaCreateInfo) + { + throw new NotImplementedException(); + } + + public Result CreateSaveDataFileSystemWithHashSalt(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo, + ref SaveMetaCreateInfo metaCreateInfo, ref HashSalt hashSalt) + { + throw new NotImplementedException(); + } + + public Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute2 attribute, ref SaveDataCreateInfo createInfo) + { + throw new NotImplementedException(); + } + + public Result ExtendSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long dataSize, long journalSize) + { + throw new NotImplementedException(); } private Result OpenSaveDataFileSystemImpl(out IFileSystem fileSystem, out ulong saveDataId, - SaveDataSpaceId spaceId, SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData) + SaveDataSpaceId spaceId, ref SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData) { bool hasFixedId = attribute.SaveId != 0 && attribute.UserId.Id == Id128.InvalidId; @@ -152,7 +159,7 @@ namespace LibHac.FsService } Result saveFsResult = FsProxyCore.OpenSaveDataFileSystem(out fileSystem, spaceId, saveDataId, - SaveDataRootPath, openReadOnly, attribute.Type, cacheExtraData); + SaveDataRootPath.ToString(), openReadOnly, attribute.Type, cacheExtraData); if (saveFsResult.IsSuccess()) return Result.Success; @@ -170,7 +177,395 @@ namespace LibHac.FsService return ResultFs.TargetNotFound; } - private bool IsSystemSaveDataId(ulong id) + public Result OpenSaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute) + { + throw new NotImplementedException(); + } + + public Result OpenReadOnlySaveDataFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, + ref SaveDataAttribute attribute) + { + throw new NotImplementedException(); + } + + public Result OpenSaveDataFileSystemBySystemSaveDataId(out IFileSystem fileSystem, SaveDataSpaceId spaceId, + ref SaveDataAttribute attribute) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + fileSystem = default; + + if (!IsSystemSaveDataId(attribute.SaveId)) return ResultFs.InvalidArgument.Log(); + + Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out _, spaceId, + ref attribute, false, true); + if (rc.IsFailure()) return rc; + + // Missing check if the current title owns the save data or can open it + + fileSystem = saveFs; + + return Result.Success; + } + + public Result ReadSaveDataFileSystemExtraData(Span extraDataBuffer, ulong saveDataId) + { + throw new NotImplementedException(); + } + + public Result ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(Span extraDataBuffer, SaveDataSpaceId spaceId, + ulong saveDataId) + { + throw new NotImplementedException(); + } + + public Result ReadSaveDataFileSystemExtraDataBySaveDataAttribute(Span extraDataBuffer, SaveDataSpaceId spaceId, + ref SaveDataAttribute2 attribute) + { + throw new NotImplementedException(); + } + + public Result WriteSaveDataFileSystemExtraData(ulong saveDataId, SaveDataSpaceId spaceId, ReadOnlySpan extraDataBuffer) + { + throw new NotImplementedException(); + } + + public Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute(ref SaveDataAttribute2 attribute, SaveDataSpaceId spaceId, + ReadOnlySpan extraDataBuffer, ReadOnlySpan maskBuffer) + { + throw new NotImplementedException(); + } + + public Result WriteSaveDataFileSystemExtraDataWithMask(ulong saveDataId, SaveDataSpaceId spaceId, ReadOnlySpan extraDataBuffer, + ReadOnlySpan maskBuffer) + { + throw new NotImplementedException(); + } + + public Result OpenImageDirectoryFileSystem(out IFileSystem fileSystem, ImageDirectoryId dirId) + { + throw new NotImplementedException(); + } + + public Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path) + { + throw new NotImplementedException(); + } + + public Result OpenBisFileSystem(out IFileSystem fileSystem, ref FsPath rootPath, BisPartitionId partitionId) + { + fileSystem = default; + + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + Result rc = PathTools.Normalize(out U8Span normalizedPath, rootPath); + if (rc.IsFailure()) return rc; + + return FsProxyCore.OpenBisFileSystem(out fileSystem, normalizedPath.ToString(), partitionId); + } + + public Result OpenBisStorage(out IStorage storage, BisPartitionId partitionId) + { + throw new NotImplementedException(); + } + + public Result InvalidateBisCache() + { + throw new NotImplementedException(); + } + + public Result OpenHostFileSystem(out IFileSystem fileSystem, ref FsPath subPath) + { + throw new NotImplementedException(); + } + + public Result OpenSdCardFileSystem(out IFileSystem fileSystem) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + return FsProxyCore.OpenSdCardFileSystem(out fileSystem); + } + + public Result FormatSdCardFileSystem() + { + throw new NotImplementedException(); + } + + public Result FormatSdCardDryRun() + { + throw new NotImplementedException(); + } + + public Result IsExFatSupported(out bool isSupported) + { + throw new NotImplementedException(); + } + + public Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId) + { + throw new NotImplementedException(); + } + + public Result OpenDeviceOperator(out IDeviceOperator deviceOperator) + { + throw new NotImplementedException(); + } + + public Result OpenSaveDataInfoReader(out ISaveDataInfoReader infoReader) + { + throw new NotImplementedException(); + } + + public Result OpenSaveDataInfoReaderBySaveDataSpaceId(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId) + { + throw new NotImplementedException(); + } + + public Result OpenSaveDataInfoReaderWithFilter(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId, + ref SaveDataFilter filter) + { + throw new NotImplementedException(); + } + + public Result FindSaveDataWithFilter(out long count, Span saveDataInfoBuffer, SaveDataSpaceId spaceId, + ref SaveDataFilter filter) + { + throw new NotImplementedException(); + } + + public Result OpenSaveDataInternalStorageFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ulong saveDataId) + { + throw new NotImplementedException(); + } + + public Result QuerySaveDataInternalStorageTotalSize(out long size, SaveDataSpaceId spaceId, ulong saveDataId) + { + throw new NotImplementedException(); + } + + public Result GetSaveDataCommitId(out long commitId, SaveDataSpaceId spaceId, ulong saveDataId) + { + throw new NotImplementedException(); + } + + public Result OpenSaveDataInfoReaderOnlyCacheStorage(out ISaveDataInfoReader infoReader) + { + throw new NotImplementedException(); + } + + public Result OpenSaveDataMetaFile(out IFile file, SaveDataSpaceId spaceId, ref SaveDataAttribute2 attribute, + SaveMetaType type) + { + throw new NotImplementedException(); + } + + public Result DeleteCacheStorage(short index) + { + throw new NotImplementedException(); + } + + public Result GetCacheStorageSize(out long dataSize, out long journalSize, short index) + { + throw new NotImplementedException(); + } + + public Result ListAccessibleSaveDataOwnerId(out int readCount, Span idBuffer, TitleId programId, int startIndex, + int bufferIdCount) + { + throw new NotImplementedException(); + } + + public Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize) + { + if (saveDataSize < 0 || saveDataJournalSize < 0) + { + return ResultFs.InvalidSize; + } + + SaveDataSize = saveDataSize; + SaveDataJournalSize = saveDataJournalSize; + + return Result.Success; + } + public Result SetSaveDataRootPath(ref FsPath path) + { + // Missing permission check + + if (StringUtils.GetLength(path.Str, FsPath.MaxLength + 1) > FsPath.MaxLength) + { + return ResultFs.TooLongPath; + } + + StringUtils.Copy(SaveDataRootPath.Str, path.Str); + + return Result.Success; + } + + public Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + return FsProxyCore.OpenContentStorageFileSystem(out fileSystem, storageId); + } + + public Result OpenCloudBackupWorkStorageFileSystem(out IFileSystem fileSystem, CloudBackupWorkStorageId storageId) + { + throw new NotImplementedException(); + } + + public Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId) + { + // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + + return FsProxyCore.OpenCustomStorageFileSystem(out fileSystem, storageId); + } + + public Result OpenGameCardFileSystem(out IFileSystem fileSystem, GameCardHandle handle, GameCardPartition partitionId) + { + throw new NotImplementedException(); + } + + public Result QuerySaveDataTotalSize(out long totalSize, long dataSize, long journalSize) + { + throw new NotImplementedException(); + } + + public Result SetCurrentPosixTimeWithTimeDifference(long time, int difference) + { + throw new NotImplementedException(); + } + + public Result GetRightsId(out RightsId rightsId, TitleId programId, StorageId storageId) + { + throw new NotImplementedException(); + } + + public Result GetRightsIdByPath(out RightsId rightsId, ref FsPath path) + { + throw new NotImplementedException(); + } + + public Result GetRightsIdAndKeyGenerationByPath(out RightsId rightsId, out byte keyGeneration, ref FsPath path) + { + throw new NotImplementedException(); + } + + public Result RegisterExternalKey(ref RightsId rightsId, ref AccessKey externalKey) + { + throw new NotImplementedException(); + } + + public Result UnregisterExternalKey(ref RightsId rightsId) + { + throw new NotImplementedException(); + } + + public Result UnregisterAllExternalKey() + { + throw new NotImplementedException(); + } + public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) + { + // todo: use struct instead of byte span + if (seed.Length != 0x10) return ResultFs.InvalidSize; + + // Missing permission check + + Result rc = FsProxyCore.SetSdCardEncryptionSeed(seed); + if (rc.IsFailure()) return rc; + + // todo: Reset save data indexer + + return Result.Success; + } + + public Result VerifySaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId, Span readBuffer) + { + throw new NotImplementedException(); + } + + public Result VerifySaveDataFileSystem(ulong saveDataId, Span readBuffer) + { + throw new NotImplementedException(); + } + + public Result CorruptSaveDataFileSystemByOffset(SaveDataSpaceId spaceId, ulong saveDataId, long offset) + { + throw new NotImplementedException(); + } + + public Result CorruptSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId) + { + throw new NotImplementedException(); + } + + public Result CorruptSaveDataFileSystem(ulong saveDataId) + { + throw new NotImplementedException(); + } + + public Result CreatePaddingFile(long size) + { + throw new NotImplementedException(); + } + + public Result DeleteAllPaddingFiles() + { + throw new NotImplementedException(); + } + + public Result DisableAutoSaveDataCreation() + { + AutoCreateSaveData = false; + + return Result.Success; + } + + public Result SetGlobalAccessLogMode(int mode) + { + throw new NotImplementedException(); + } + + public Result GetGlobalAccessLogMode(out int mode) + { + throw new NotImplementedException(); + } + + public Result GetProgramIndexForAccessLog(out int programIndex, out int programCount) + { + throw new NotImplementedException(); + } + + public Result OutputAccessLogToSdCard(U8Span logString) + { + throw new NotImplementedException(); + } + + public Result RegisterUpdatePartition() + { + throw new NotImplementedException(); + } + + public Result OpenRegisteredUpdatePartition(out IFileSystem fileSystem) + { + throw new NotImplementedException(); + } + + public Result OverrideSaveDataTransferTokenSignVerificationKey(ReadOnlySpan key) + { + throw new NotImplementedException(); + } + + public Result SetSdCardAccessibility(bool isAccessible) + { + throw new NotImplementedException(); + } + + public Result IsSdCardAccessible(out bool isAccessible) + { + throw new NotImplementedException(); + } + + private static bool IsSystemSaveDataId(ulong id) { return (long)id < 0; } diff --git a/src/LibHac/FsService/FileSystemServer.cs b/src/LibHac/FsService/FileSystemServer.cs index 849ba674..09d17f40 100644 --- a/src/LibHac/FsService/FileSystemServer.cs +++ b/src/LibHac/FsService/FileSystemServer.cs @@ -47,7 +47,7 @@ namespace LibHac.FsService return new FileSystemClient(this, timer); } - public FileSystemProxy CreateFileSystemProxyService() + public IFileSystemProxy CreateFileSystemProxyService() { return new FileSystemProxy(FsProxyCore, FsClient); } diff --git a/src/LibHac/FsSystem/FsPath.cs b/src/LibHac/FsSystem/FsPath.cs index b40e5b60..af82bb49 100644 --- a/src/LibHac/FsSystem/FsPath.cs +++ b/src/LibHac/FsSystem/FsPath.cs @@ -15,6 +15,7 @@ namespace LibHac.FsSystem public Span Str => SpanHelpers.CreateSpan(ref _str, MaxLength + 1); + public static implicit operator U8Span(FsPath value) => new U8Span(value.Str); public override string ToString() => StringUtils.Utf8ZToString(Str); } } diff --git a/src/LibHac/FsSystem/PathTools.cs b/src/LibHac/FsSystem/PathTools.cs index 3a0fcd51..742d0b51 100644 --- a/src/LibHac/FsSystem/PathTools.cs +++ b/src/LibHac/FsSystem/PathTools.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; +using LibHac.Common; using LibHac.Fs; #if HAS_FILE_SYSTEM_NAME @@ -51,6 +52,20 @@ namespace LibHac.FsSystem return normalized; } + public static Result Normalize(out U8Span normalizedPath, U8Span path) + { + if (path.Length == 0) + { + normalizedPath = path; + return Result.Success; + } + + // Todo: optimize + normalizedPath = new U8Span(Normalize(path.ToString())); + + return Result.Success; + } + // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. From 955fff8efc41293fd20dfe8e40318a3dc5eae839 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Wed, 25 Sep 2019 17:16:59 -0500 Subject: [PATCH 28/46] Add FileHandleStorage and a new SubStorage class --- src/LibHac/Fs/FileHandleStorage.cs | 98 +++++++++++++++++++++++++ src/LibHac/Fs/FileSystemClient.File.cs | 2 +- src/LibHac/Fs/FileSystemManager.cs | 10 +-- src/LibHac/Fs/FileSystemManagerUtils.cs | 2 +- src/LibHac/Fs/StorageBase.cs | 20 +++++ src/LibHac/Fs/SubStorage2.cs | 85 +++++++++++++++++++++ src/LibHac/FsSystem/AesXtsFile.cs | 1 + src/LibHac/FsSystem/AesXtsFileSystem.cs | 6 +- 8 files changed, 215 insertions(+), 9 deletions(-) create mode 100644 src/LibHac/Fs/FileHandleStorage.cs create mode 100644 src/LibHac/Fs/StorageBase.cs create mode 100644 src/LibHac/Fs/SubStorage2.cs diff --git a/src/LibHac/Fs/FileHandleStorage.cs b/src/LibHac/Fs/FileHandleStorage.cs new file mode 100644 index 00000000..04052833 --- /dev/null +++ b/src/LibHac/Fs/FileHandleStorage.cs @@ -0,0 +1,98 @@ +using System; + +namespace LibHac.Fs +{ + public class FileHandleStorage : StorageBase + { + private const long InvalidSize = -1; + private readonly object _locker = new object(); + + private FileSystemManager FsManager { get; } + private FileHandle Handle { get; } + private long FileSize { get; set; } = InvalidSize; + private bool CloseHandle { get; } + + public FileHandleStorage(FileHandle handle) : this(handle, false) { } + + public FileHandleStorage(FileHandle handle, bool closeHandleOnDispose) + { + Handle = handle; + CloseHandle = closeHandleOnDispose; + FsManager = Handle.File.Parent.FsManager; + } + + public override Result Read(long offset, Span destination) + { + lock (_locker) + { + if (destination.Length == 0) return Result.Success; + + Result rc = UpdateSize(); + if (rc.IsFailure()) return rc; + + if (destination.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); + if (!IsRangeValid(offset, destination.Length, FileSize)) return ResultFs.ValueOutOfRange.Log(); + + return FsManager.ReadFile(Handle, offset, destination); + } + } + + public override Result Write(long offset, ReadOnlySpan source) + { + lock (_locker) + { + if (source.Length == 0) return Result.Success; + + Result rc = UpdateSize(); + if (rc.IsFailure()) return rc; + + if (source.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); + if (!IsRangeValid(offset, source.Length, FileSize)) return ResultFs.ValueOutOfRange.Log(); + + return FsManager.WriteFile(Handle, offset, source); + } + } + + public override Result Flush() + { + return FsManager.FlushFile(Handle); + } + + public override Result SetSize(long size) + { + FileSize = InvalidSize; + + return FsManager.SetFileSize(Handle, size); + } + + public override Result GetSize(out long size) + { + size = default; + + Result rc = UpdateSize(); + if (rc.IsFailure()) return rc; + + size = FileSize; + return Result.Success; + } + + private Result UpdateSize() + { + if (FileSize != InvalidSize) return Result.Success; + + Result rc = FsManager.GetFileSize(out long fileSize, Handle); + if (rc.IsFailure()) return rc; + + FileSize = fileSize; + return Result.Success; + } + + public override void Dispose() + { + if (CloseHandle) + { + FsManager.CloseFile(Handle); + } + } + } +} diff --git a/src/LibHac/Fs/FileSystemClient.File.cs b/src/LibHac/Fs/FileSystemClient.File.cs index fa4bbbc0..83cd3760 100644 --- a/src/LibHac/Fs/FileSystemClient.File.cs +++ b/src/LibHac/Fs/FileSystemClient.File.cs @@ -26,7 +26,7 @@ namespace LibHac.Fs public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source, WriteOption options) { - return FsManager.WriteFile(handle, source, offset, options); + return FsManager.WriteFile(handle, offset, source, options); } public Result FlushFile(FileHandle handle) diff --git a/src/LibHac/Fs/FileSystemManager.cs b/src/LibHac/Fs/FileSystemManager.cs index 29e33b55..0a685f34 100644 --- a/src/LibHac/Fs/FileSystemManager.cs +++ b/src/LibHac/Fs/FileSystemManager.cs @@ -433,12 +433,12 @@ namespace LibHac.Fs return rc; } - public Result WriteFile(FileHandle handle, ReadOnlySpan source, long offset) + public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source) { - return WriteFile(handle, source, offset, WriteOption.None); + return WriteFile(handle, offset, source, WriteOption.None); } - public Result WriteFile(FileHandle handle, ReadOnlySpan source, long offset, WriteOption option) + public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source, WriteOption option) { Result rc; @@ -607,9 +607,9 @@ namespace LibHac.Fs mountName = path.Slice(0, mountLen); - if (mountLen + 2 < path.Length) + if (mountLen + 1 < path.Length) { - subPath = path.Slice(mountLen + 2); + subPath = path.Slice(mountLen + 1); } else { diff --git a/src/LibHac/Fs/FileSystemManagerUtils.cs b/src/LibHac/Fs/FileSystemManagerUtils.cs index 4aa01e30..be795316 100644 --- a/src/LibHac/Fs/FileSystemManagerUtils.cs +++ b/src/LibHac/Fs/FileSystemManagerUtils.cs @@ -76,7 +76,7 @@ namespace LibHac.Fs rc = fs.ReadFile(out long _, sourceHandle, offset, buf); if (rc.IsFailure()) return rc; - rc = fs.WriteFile(destHandle, buf, offset); + rc = fs.WriteFile(destHandle, offset, buf); if (rc.IsFailure()) return rc; logger?.ReportAdd(toRead); diff --git a/src/LibHac/Fs/StorageBase.cs b/src/LibHac/Fs/StorageBase.cs new file mode 100644 index 00000000..732b611f --- /dev/null +++ b/src/LibHac/Fs/StorageBase.cs @@ -0,0 +1,20 @@ +using System; + +namespace LibHac.Fs +{ + public abstract class StorageBase : IStorage + { + public abstract Result Read(long offset, Span destination); + public abstract Result Write(long offset, ReadOnlySpan source); + public abstract Result Flush(); + public abstract Result SetSize(long size); + public abstract Result GetSize(out long size); + + public virtual void Dispose() { } + + public static bool IsRangeValid(long offset, long size, long totalSize) + { + return size <= totalSize && offset <= totalSize - size; + } + } +} diff --git a/src/LibHac/Fs/SubStorage2.cs b/src/LibHac/Fs/SubStorage2.cs new file mode 100644 index 00000000..e919a04e --- /dev/null +++ b/src/LibHac/Fs/SubStorage2.cs @@ -0,0 +1,85 @@ +using System; + +namespace LibHac.Fs +{ + public class SubStorage2 : StorageBase + { + private IStorage BaseStorage { get; } + private long Offset { get; } + private long Size { get; set; } + public bool IsResizable { get; set; } + + public SubStorage2(IStorage baseStorage, long offset, long size) + { + BaseStorage = baseStorage; + Offset = offset; + Size = size; + } + + public SubStorage2(SubStorage2 baseStorage, long offset, long size) + { + BaseStorage = baseStorage.BaseStorage; + Offset = baseStorage.Offset + offset; + Size = size; + } + + public override Result Read(long offset, Span destination) + { + if (BaseStorage == null) return ResultFs.Result6902.Log(); + if (destination.Length == 0) return Result.Success; + if (Size < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); + if (!IsRangeValid(offset, destination.Length, Size)) return ResultFs.ValueOutOfRange.Log(); + + return BaseStorage.Read(Offset + offset, destination); + } + + public override Result Write(long offset, ReadOnlySpan source) + { + if (BaseStorage == null) return ResultFs.Result6902.Log(); + if (source.Length == 0) return Result.Success; + if (Size < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); + if (!IsRangeValid(offset, source.Length, Size)) return ResultFs.ValueOutOfRange.Log(); + + return BaseStorage.Write(Offset + offset, source); + } + + public override Result Flush() + { + if (BaseStorage == null) return ResultFs.Result6902.Log(); + + return BaseStorage.Flush(); + } + + public override Result SetSize(long size) + { + if (BaseStorage == null) return ResultFs.Result6902.Log(); + if (!IsResizable) return ResultFs.SubStorageNotResizable.Log(); + if (size < 0 || Offset < 0) return ResultFs.ValueOutOfRange.Log(); + + Result rc = BaseStorage.GetSize(out long baseSize); + if (rc.IsFailure()) return rc; + + if (baseSize != Offset + Size) + { + // SubStorage cannot be resized unless it is located at the end of the base storage. + return ResultFs.SubStorageNotResizableMiddleOfFile.Log(); + } + + rc = BaseStorage.SetSize(Offset + size); + if (rc.IsFailure()) return rc; + + Size = size; + return Result.Success; + } + + public override Result GetSize(out long size) + { + size = default; + + if (BaseStorage == null) return ResultFs.Result6902.Log(); + + size = Size; + return Result.Success; + } + } +} diff --git a/src/LibHac/FsSystem/AesXtsFile.cs b/src/LibHac/FsSystem/AesXtsFile.cs index 00fb3403..9455126a 100644 --- a/src/LibHac/FsSystem/AesXtsFile.cs +++ b/src/LibHac/FsSystem/AesXtsFile.cs @@ -63,6 +63,7 @@ namespace LibHac.FsSystem rc = BaseStorage.Read(offset, destination.Slice(0, (int)toRead)); if (rc.IsFailure()) return rc; + bytesRead = toRead; return Result.Success; } diff --git a/src/LibHac/FsSystem/AesXtsFileSystem.cs b/src/LibHac/FsSystem/AesXtsFileSystem.cs index ccfca772..118200bb 100644 --- a/src/LibHac/FsSystem/AesXtsFileSystem.cs +++ b/src/LibHac/FsSystem/AesXtsFileSystem.cs @@ -49,11 +49,13 @@ namespace LibHac.FsSystem public Result CreateFile(string path, long size, CreateFileOptions options, byte[] key) { long containerSize = AesXtsFile.HeaderLength + Util.AlignUp(size, 0x10); - BaseFileSystem.CreateFile(path, containerSize, options); + + Result rc = BaseFileSystem.CreateFile(path, containerSize, options); + if (rc.IsFailure()) return rc; var header = new AesXtsFileHeader(key, size, path, KekSource, ValidationKey); - Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write); + rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write); if (rc.IsFailure()) return rc; using (baseFile) From 00eb9887937c6f04bb4b4c41165a83dbb498bcee Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Wed, 25 Sep 2019 17:50:07 -0500 Subject: [PATCH 29/46] Move FileSystemManager into FileSystemClient --- src/LibHac/Fs/Accessors/FileSystemAccessor.cs | 6 +- src/LibHac/Fs/DirectoryHandle.cs | 2 +- src/LibHac/Fs/FileHandle.cs | 2 +- src/LibHac/Fs/FileHandleStorage.cs | 16 +- src/LibHac/Fs/FileSystemClient.Directory.cs | 32 +- src/LibHac/Fs/FileSystemClient.File.cs | 109 ++- src/LibHac/Fs/FileSystemClient.FileSystem.cs | 271 +++++++- src/LibHac/Fs/FileSystemClient.cs | 152 +++- ...nagerUtils.cs => FileSystemClientUtils.cs} | 24 +- src/LibHac/Fs/FileSystemManager.cs | 652 ------------------ src/LibHac/Horizon.cs | 9 +- src/hactoolnet/FsUtils.cs | 10 +- src/hactoolnet/ProcessNca.cs | 6 +- src/hactoolnet/ProcessSave.cs | 2 +- 14 files changed, 564 insertions(+), 729 deletions(-) rename src/LibHac/Fs/{FileSystemManagerUtils.cs => FileSystemClientUtils.cs} (90%) delete mode 100644 src/LibHac/Fs/FileSystemManager.cs diff --git a/src/LibHac/Fs/Accessors/FileSystemAccessor.cs b/src/LibHac/Fs/Accessors/FileSystemAccessor.cs index f89b4d61..a51f1e6e 100644 --- a/src/LibHac/Fs/Accessors/FileSystemAccessor.cs +++ b/src/LibHac/Fs/Accessors/FileSystemAccessor.cs @@ -10,7 +10,7 @@ namespace LibHac.Fs.Accessors public string Name { get; } private IFileSystem FileSystem { get; } - internal FileSystemManager FsManager { get; } + internal FileSystemClient FsClient { get; } private ICommonMountNameGenerator MountNameGenerator { get; } private HashSet OpenFiles { get; } = new HashSet(); @@ -20,11 +20,11 @@ namespace LibHac.Fs.Accessors internal bool IsAccessLogEnabled { get; set; } - public FileSystemAccessor(string name, IFileSystem baseFileSystem, FileSystemManager fsManager, ICommonMountNameGenerator nameGenerator) + public FileSystemAccessor(string name, IFileSystem baseFileSystem, FileSystemClient fsClient, ICommonMountNameGenerator nameGenerator) { Name = name; FileSystem = baseFileSystem; - FsManager = fsManager; + FsClient = fsClient; MountNameGenerator = nameGenerator; } diff --git a/src/LibHac/Fs/DirectoryHandle.cs b/src/LibHac/Fs/DirectoryHandle.cs index e76ac017..1a8f606b 100644 --- a/src/LibHac/Fs/DirectoryHandle.cs +++ b/src/LibHac/Fs/DirectoryHandle.cs @@ -16,7 +16,7 @@ namespace LibHac.Fs public void Dispose() { - Directory.Parent.FsManager.CloseDirectory(this); + Directory.Parent.FsClient.CloseDirectory(this); } } } diff --git a/src/LibHac/Fs/FileHandle.cs b/src/LibHac/Fs/FileHandle.cs index acb4e211..eb927d5b 100644 --- a/src/LibHac/Fs/FileHandle.cs +++ b/src/LibHac/Fs/FileHandle.cs @@ -16,7 +16,7 @@ namespace LibHac.Fs public void Dispose() { - File.Parent.FsManager.CloseFile(this); + File.Parent.FsClient.CloseFile(this); } } } diff --git a/src/LibHac/Fs/FileHandleStorage.cs b/src/LibHac/Fs/FileHandleStorage.cs index 04052833..729e2d78 100644 --- a/src/LibHac/Fs/FileHandleStorage.cs +++ b/src/LibHac/Fs/FileHandleStorage.cs @@ -7,7 +7,7 @@ namespace LibHac.Fs private const long InvalidSize = -1; private readonly object _locker = new object(); - private FileSystemManager FsManager { get; } + private FileSystemClient FsClient { get; } private FileHandle Handle { get; } private long FileSize { get; set; } = InvalidSize; private bool CloseHandle { get; } @@ -18,7 +18,7 @@ namespace LibHac.Fs { Handle = handle; CloseHandle = closeHandleOnDispose; - FsManager = Handle.File.Parent.FsManager; + FsClient = Handle.File.Parent.FsClient; } public override Result Read(long offset, Span destination) @@ -33,7 +33,7 @@ namespace LibHac.Fs if (destination.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); if (!IsRangeValid(offset, destination.Length, FileSize)) return ResultFs.ValueOutOfRange.Log(); - return FsManager.ReadFile(Handle, offset, destination); + return FsClient.ReadFile(Handle, offset, destination); } } @@ -49,20 +49,20 @@ namespace LibHac.Fs if (source.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); if (!IsRangeValid(offset, source.Length, FileSize)) return ResultFs.ValueOutOfRange.Log(); - return FsManager.WriteFile(Handle, offset, source); + return FsClient.WriteFile(Handle, offset, source); } } public override Result Flush() { - return FsManager.FlushFile(Handle); + return FsClient.FlushFile(Handle); } public override Result SetSize(long size) { FileSize = InvalidSize; - return FsManager.SetFileSize(Handle, size); + return FsClient.SetFileSize(Handle, size); } public override Result GetSize(out long size) @@ -80,7 +80,7 @@ namespace LibHac.Fs { if (FileSize != InvalidSize) return Result.Success; - Result rc = FsManager.GetFileSize(out long fileSize, Handle); + Result rc = FsClient.GetFileSize(out long fileSize, Handle); if (rc.IsFailure()) return rc; FileSize = fileSize; @@ -91,7 +91,7 @@ namespace LibHac.Fs { if (CloseHandle) { - FsManager.CloseFile(Handle); + FsClient.CloseFile(Handle); } } } diff --git a/src/LibHac/Fs/FileSystemClient.Directory.cs b/src/LibHac/Fs/FileSystemClient.Directory.cs index 90253dfe..499b7150 100644 --- a/src/LibHac/Fs/FileSystemClient.Directory.cs +++ b/src/LibHac/Fs/FileSystemClient.Directory.cs @@ -6,17 +6,43 @@ namespace LibHac.Fs { public Result GetDirectoryEntryCount(out long count, DirectoryHandle handle) { - return FsManager.GetDirectoryEntryCount(out count, handle); + return handle.Directory.GetEntryCount(out count); } public Result ReadDirectory(out long entriesRead, Span entryBuffer, DirectoryHandle handle) { - return FsManager.ReadDirectory(out entriesRead, entryBuffer, handle); + Result rc; + + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) + { + TimeSpan startTime = Time.GetCurrent(); + rc = handle.Directory.Read(out entriesRead, entryBuffer); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, handle, string.Empty); + } + else + { + rc = handle.Directory.Read(out entriesRead, entryBuffer); + } + + return rc; } public void CloseDirectory(DirectoryHandle handle) { - FsManager.CloseDirectory(handle); + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) + { + TimeSpan startTime = Time.GetCurrent(); + handle.Directory.Dispose(); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); + } + else + { + handle.Directory.Dispose(); + } } } } diff --git a/src/LibHac/Fs/FileSystemClient.File.cs b/src/LibHac/Fs/FileSystemClient.File.cs index 83cd3760..3e508426 100644 --- a/src/LibHac/Fs/FileSystemClient.File.cs +++ b/src/LibHac/Fs/FileSystemClient.File.cs @@ -6,52 +6,135 @@ namespace LibHac.Fs { public Result ReadFile(FileHandle handle, long offset, Span destination) { - return FsManager.ReadFile(handle, offset, destination); + return ReadFile(handle, offset, destination, ReadOption.None); } - public Result ReadFile(FileHandle handle, long offset, Span destination, ReadOption options) + public Result ReadFile(FileHandle handle, long offset, Span destination, ReadOption option) { - return FsManager.ReadFile(handle, offset, destination, options); + Result rc = ReadFile(out long bytesRead, handle, offset, destination, option); + if (rc.IsFailure()) return rc; + + if (bytesRead == destination.Length) return Result.Success; + + return ResultFs.ValueOutOfRange.Log(); } public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination) { - return FsManager.ReadFile(out bytesRead, handle, offset, destination); + return ReadFile(out bytesRead, handle, offset, destination, ReadOption.None); } - public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination, ReadOption options) + public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination, ReadOption option) { - return FsManager.ReadFile(out bytesRead, handle, offset, destination, options); + Result rc; + + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) + { + TimeSpan startTime = Time.GetCurrent(); + rc = handle.File.Read(out bytesRead, offset, destination, option); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, handle, $", offset: {offset}, size: {destination.Length}"); + } + else + { + rc = handle.File.Read(out bytesRead, offset, destination, option); + } + + return rc; } - public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source, WriteOption options) + public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source) { - return FsManager.WriteFile(handle, offset, source, options); + return WriteFile(handle, offset, source, WriteOption.None); + } + + public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source, WriteOption option) + { + Result rc; + + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) + { + TimeSpan startTime = Time.GetCurrent(); + rc = handle.File.Write(offset, source, option); + TimeSpan endTime = Time.GetCurrent(); + + string optionString = (option & WriteOption.Flush) == 0 ? "" : $", write_option: {option}"; + + OutputAccessLog(rc, startTime, endTime, handle, $", offset: {offset}, size: {source.Length}{optionString}"); + } + else + { + rc = handle.File.Write(offset, source, option); + } + + return rc; } public Result FlushFile(FileHandle handle) { - return FsManager.FlushFile(handle); + Result rc; + + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) + { + TimeSpan startTime = Time.GetCurrent(); + rc = handle.File.Flush(); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, handle, string.Empty); + } + else + { + rc = handle.File.Flush(); + } + + return rc; } public Result GetFileSize(out long fileSize, FileHandle handle) { - return FsManager.GetFileSize(out fileSize, handle); + return handle.File.GetSize(out fileSize); } public Result SetFileSize(FileHandle handle, long size) { - return FsManager.SetFileSize(handle, size); + Result rc; + + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) + { + TimeSpan startTime = Time.GetCurrent(); + rc = handle.File.SetSize(size); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, handle, $", size: {size}"); + } + else + { + rc = handle.File.SetSize(size); + } + + return rc; } public OpenMode GetFileOpenMode(FileHandle handle) { - return FsManager.GetFileOpenMode(handle); + return handle.File.OpenMode; } public void CloseFile(FileHandle handle) { - FsManager.CloseFile(handle); + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) + { + TimeSpan startTime = Time.GetCurrent(); + handle.File.Dispose(); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); + } + else + { + handle.File.Dispose(); + } } } } diff --git a/src/LibHac/Fs/FileSystemClient.FileSystem.cs b/src/LibHac/Fs/FileSystemClient.FileSystem.cs index 2f5707f1..7ed7e6a9 100644 --- a/src/LibHac/Fs/FileSystemClient.FileSystem.cs +++ b/src/LibHac/Fs/FileSystemClient.FileSystem.cs @@ -1,10 +1,29 @@ +using System; +using LibHac.Fs.Accessors; + namespace LibHac.Fs { public partial class FileSystemClient { public Result CreateDirectory(string path) { - return FsManager.CreateDirectory(path); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.CreateDirectory(subPath.ToString()); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + } + else + { + rc = fileSystem.CreateDirectory(subPath.ToString()); + } + + return rc; } public Result CreateFile(string path, long size) @@ -14,67 +33,289 @@ namespace LibHac.Fs public Result CreateFile(string path, long size, CreateFileOptions options) { - return FsManager.CreateFile(path, size, options); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.CreateFile(subPath.ToString(), size, options); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\", size: {size}"); + } + else + { + rc = fileSystem.CreateFile(subPath.ToString(), size, options); + } + + return rc; } public Result DeleteDirectory(string path) { - return FsManager.DeleteDirectory(path); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.DeleteDirectory(subPath.ToString()); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + } + else + { + rc = fileSystem.DeleteDirectory(subPath.ToString()); + } + + return rc; } public Result DeleteDirectoryRecursively(string path) { - return FsManager.DeleteDirectoryRecursively(path); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + } + else + { + rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); + } + + return rc; } public Result CleanDirectoryRecursively(string path) { - return FsManager.CleanDirectoryRecursively(path); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + } + else + { + rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); + } + + return rc; } public Result DeleteFile(string path) { - return FsManager.DeleteFile(path); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.DeleteFile(subPath.ToString()); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + } + else + { + rc = fileSystem.DeleteFile(subPath.ToString()); + } + + return rc; } public Result RenameDirectory(string oldPath, string newPath) { - return FsManager.RenameDirectory(oldPath, newPath); + Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); + if (rc.IsFailure()) return rc; + + rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); + if (rc.IsFailure()) return rc; + + if (oldFileSystem != newFileSystem) + { + return ResultFs.DifferentDestFileSystem.Log(); + } + + if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); + } + else + { + rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); + } + + return rc; } public Result RenameFile(string oldPath, string newPath) { - return FsManager.RenameFile(oldPath, newPath); + Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); + if (rc.IsFailure()) return rc; + + rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); + if (rc.IsFailure()) return rc; + + if (oldFileSystem != newFileSystem) + { + return ResultFs.DifferentDestFileSystem.Log(); + } + + if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); + } + else + { + rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); + } + + return rc; } public Result GetEntryType(out DirectoryEntryType type, string path) { - return FsManager.GetEntryType(out type, path); + type = default; + + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.GetEntryType(out type, subPath.ToString()); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + } + else + { + rc = fileSystem.GetEntryType(out type, subPath.ToString()); + } + + return rc; } public Result OpenFile(out FileHandle handle, string path, OpenMode mode) { - return FsManager.OpenFile(out handle, path, mode); + handle = default; + + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); + handle = new FileHandle(file); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); + } + else + { + rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); + handle = new FileHandle(file); + } + + return rc; } public Result OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) { - return FsManager.OpenDirectory(out handle, path, mode); + handle = default; + + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); + handle = new DirectoryHandle(dir); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); + } + else + { + rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); + handle = new DirectoryHandle(dir); + } + + return rc; } public Result GetFreeSpaceSize(out long freeSpace, string path) { - return FsManager.GetFreeSpaceSize(out freeSpace, path); + freeSpace = default; + + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + return fileSystem.GetFreeSpaceSize(out freeSpace, subPath.ToString()); } public Result GetTotalSpaceSize(out long totalSpace, string path) { - return FsManager.GetTotalSpaceSize(out totalSpace, path); + totalSpace = default; + + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + return fileSystem.GetTotalSpaceSize(out totalSpace, subPath.ToString()); + } + + public Result GetFileTimeStamp(out FileTimeStampRaw timeStamp, string path) + { + timeStamp = default; + + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + return fileSystem.GetFileTimeStampRaw(out timeStamp, subPath.ToString()); } public Result Commit(string mountName) { - return FsManager.Commit(mountName); + Result rc = MountTable.Find(mountName, out FileSystemAccessor fileSystem); + if (rc.IsFailure()) return rc; + + if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = fileSystem.Commit(); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\""); + } + else + { + rc = fileSystem.Commit(); + } + + return rc; } } -} \ No newline at end of file +} diff --git a/src/LibHac/Fs/FileSystemClient.cs b/src/LibHac/Fs/FileSystemClient.cs index 76ce211b..8ac67876 100644 --- a/src/LibHac/Fs/FileSystemClient.cs +++ b/src/LibHac/Fs/FileSystemClient.cs @@ -1,5 +1,9 @@ -using LibHac.Common; +using System; +using System.Runtime.CompilerServices; +using LibHac.Common; +using LibHac.Fs.Accessors; using LibHac.FsService; +using LibHac.FsSystem; namespace LibHac.Fs { @@ -7,14 +11,24 @@ namespace LibHac.Fs { private FileSystemServer FsSrv { get; } private IFileSystemProxy FsProxy { get; set; } - private FileSystemManager FsManager { get; } private readonly object _fspInitLocker = new object(); + internal ITimeSpanGenerator Time { get; } + private IAccessLog AccessLog { get; set; } + private bool AccessLogEnabled { get; set; } + + internal MountTable MountTable { get; } = new MountTable(); + + public FileSystemClient(ITimeSpanGenerator timer) + { + Time = timer; + } + public FileSystemClient(FileSystemServer fsServer, ITimeSpanGenerator timer) { FsSrv = fsServer; - FsManager = new FileSystemManager(timer); + Time = timer; } public IFileSystemProxy GetFileSystemProxyServiceObject() @@ -25,6 +39,11 @@ namespace LibHac.Fs { if (FsProxy != null) return FsProxy; + if (FsSrv == null) + { + throw new InvalidOperationException("Client was not initialized with a server object."); + } + FsProxy = FsSrv.CreateFileSystemProxyService(); return FsProxy; @@ -33,12 +52,135 @@ namespace LibHac.Fs public Result Register(U8Span mountName, IFileSystem fileSystem) { - return FsManager.Register(mountName, fileSystem); + return Register(mountName, fileSystem, null); } public Result Register(U8Span mountName, IFileSystem fileSystem, ICommonMountNameGenerator nameGenerator) { - return FsManager.Register(mountName, fileSystem, nameGenerator); + var accessor = new FileSystemAccessor(mountName.ToString(), fileSystem, this, nameGenerator); + + Result rc = MountTable.Mount(accessor); + if (rc.IsFailure()) return rc; + + accessor.IsAccessLogEnabled = IsEnabledAccessLog(); + return Result.Success; + } + + public void Unmount(string mountName) + { + Result rc; + + if (IsEnabledAccessLog() && IsEnabledFileSystemAccessorAccessLog(mountName)) + { + TimeSpan startTime = Time.GetCurrent(); + + rc = MountTable.Unmount(mountName); + + TimeSpan endTime = Time.GetCurrent(); + OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\""); + } + else + { + rc = MountTable.Unmount(mountName); + } + + rc.ThrowIfFailure(); + } + + public void SetAccessLog(bool isEnabled, IAccessLog accessLog = null) + { + AccessLogEnabled = isEnabled; + + if (accessLog != null) AccessLog = accessLog; + } + + internal Result FindFileSystem(ReadOnlySpan path, out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) + { + fileSystem = default; + + Result rc = GetMountName(path, out ReadOnlySpan mountName, out subPath); + if (rc.IsFailure()) return rc; + + rc = MountTable.Find(mountName.ToString(), out fileSystem); + if (rc.IsFailure()) return rc; + + return Result.Success; + } + + internal static Result GetMountName(ReadOnlySpan path, out ReadOnlySpan mountName, out ReadOnlySpan subPath) + { + int mountLen = 0; + int maxMountLen = Math.Min(path.Length, PathTools.MountNameLength); + + for (int i = 0; i < maxMountLen; i++) + { + if (path[i] == PathTools.MountSeparator) + { + mountLen = i; + break; + } + } + + if (mountLen == 0) + { + mountName = default; + subPath = default; + + return ResultFs.InvalidMountName; + } + + mountName = path.Slice(0, mountLen); + + if (mountLen + 1 < path.Length) + { + subPath = path.Slice(mountLen + 1); + } + else + { + subPath = default; + } + + return Result.Success; + } + + internal bool IsEnabledAccessLog() + { + return AccessLogEnabled && AccessLog != null && Time != null; + } + + internal bool IsEnabledFileSystemAccessorAccessLog(string mountName) + { + if (MountTable.Find(mountName, out FileSystemAccessor accessor).IsFailure()) + { + return true; + } + + return accessor.IsAccessLogEnabled; + } + + internal bool IsEnabledHandleAccessLog(FileHandle handle) + { + return handle.File.Parent.IsAccessLogEnabled; + } + + internal bool IsEnabledHandleAccessLog(DirectoryHandle handle) + { + return handle.Directory.Parent.IsAccessLogEnabled; + } + + internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "") + { + AccessLog.Log(result, startTime, endTime, 0, message, caller); + } + + internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "") + { + AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller); + } + + internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "") + { + AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller); } } } diff --git a/src/LibHac/Fs/FileSystemManagerUtils.cs b/src/LibHac/Fs/FileSystemClientUtils.cs similarity index 90% rename from src/LibHac/Fs/FileSystemManagerUtils.cs rename to src/LibHac/Fs/FileSystemClientUtils.cs index be795316..0165f354 100644 --- a/src/LibHac/Fs/FileSystemManagerUtils.cs +++ b/src/LibHac/Fs/FileSystemClientUtils.cs @@ -7,9 +7,9 @@ using LibHac.FsSystem; namespace LibHac.Fs { - public static class FileSystemManagerUtils + public static class FileSystemClientUtils { - public static Result CopyDirectory(this FileSystemManager fs, string sourcePath, string destPath, + public static Result CopyDirectory(this FileSystemClient fs, string sourcePath, string destPath, CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null) { Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All); @@ -44,7 +44,7 @@ namespace LibHac.Fs return Result.Success; } - public static Result CopyFile(this FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) + public static Result CopyFile(this FileSystemClient fs, string sourcePath, string destPath, IProgressReport logger = null) { Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read); if (rc.IsFailure()) return rc; @@ -96,17 +96,17 @@ namespace LibHac.Fs return Result.Success; } - public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path) + public static IEnumerable EnumerateEntries(this FileSystemClient fs, string path) { return fs.EnumerateEntries(path, "*"); } - public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path, string searchPattern) + public static IEnumerable EnumerateEntries(this FileSystemClient fs, string path, string searchPattern) { return fs.EnumerateEntries(path, searchPattern, SearchOptions.RecurseSubdirectories); } - public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path, string searchPattern, SearchOptions searchOptions) + public static IEnumerable EnumerateEntries(this FileSystemClient fs, string path, string searchPattern, SearchOptions searchOptions) { bool ignoreCase = searchOptions.HasFlag(SearchOptions.CaseInsensitive); bool recurse = searchOptions.HasFlag(SearchOptions.RecurseSubdirectories); @@ -141,21 +141,21 @@ namespace LibHac.Fs } } - public static bool DirectoryExists(this FileSystemManager fs, string path) + public static bool DirectoryExists(this FileSystemClient fs, string path) { Result rc = fs.GetEntryType(out DirectoryEntryType type, path); return (rc.IsSuccess() && type == DirectoryEntryType.Directory); } - public static bool FileExists(this FileSystemManager fs, string path) + public static bool FileExists(this FileSystemClient fs, string path) { Result rc = fs.GetEntryType(out DirectoryEntryType type, path); return (rc.IsSuccess() && type == DirectoryEntryType.File); } - public static void EnsureDirectoryExists(this FileSystemManager fs, string path) + public static void EnsureDirectoryExists(this FileSystemClient fs, string path) { path = PathTools.Normalize(path); if (fs.DirectoryExists(path)) return; @@ -195,12 +195,12 @@ namespace LibHac.Fs fs.CreateDirectory(path); } - public static void CreateOrOverwriteFile(this FileSystemManager fs, string path, long size) + public static void CreateOrOverwriteFile(this FileSystemClient fs, string path, long size) { fs.CreateOrOverwriteFile(path, size, CreateFileOptions.None); } - public static void CreateOrOverwriteFile(this FileSystemManager fs, string path, long size, CreateFileOptions options) + public static void CreateOrOverwriteFile(this FileSystemClient fs, string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); @@ -209,7 +209,7 @@ namespace LibHac.Fs fs.CreateFile(path, size, CreateFileOptions.None); } - internal static bool IsEnabledFileSystemAccessorAccessLog(this FileSystemManager fs, string mountName) + internal static bool IsEnabledFileSystemAccessorAccessLog(this FileSystemClient fs, string mountName) { if (fs.MountTable.Find(mountName, out FileSystemAccessor accessor).IsFailure()) { diff --git a/src/LibHac/Fs/FileSystemManager.cs b/src/LibHac/Fs/FileSystemManager.cs deleted file mode 100644 index 0a685f34..00000000 --- a/src/LibHac/Fs/FileSystemManager.cs +++ /dev/null @@ -1,652 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using LibHac.Common; -using LibHac.Fs.Accessors; -using LibHac.FsSystem; - -namespace LibHac.Fs -{ - // Todo: Access log for FindFileSystem - public class FileSystemManager - { - internal Horizon Os { get; } - internal ITimeSpanGenerator Time { get; } - private IAccessLog AccessLog { get; set; } - - internal MountTable MountTable { get; } = new MountTable(); - - private bool AccessLogEnabled { get; set; } - - public FileSystemManager(Horizon os) - { - Os = os; - } - - public FileSystemManager(Horizon os, ITimeSpanGenerator timer) - { - Os = os; - Time = timer; - } - - public FileSystemManager(ITimeSpanGenerator timer) - { - Time = timer; - } - - public Result Register(U8Span mountName, IFileSystem fileSystem) - { - return Register(mountName, fileSystem, null); - } - - public Result Register(U8Span mountName, IFileSystem fileSystem, ICommonMountNameGenerator nameGenerator) - { - var accessor = new FileSystemAccessor(mountName.ToString(), fileSystem, this, nameGenerator); - - Result rc = MountTable.Mount(accessor); - if (rc.IsFailure()) return rc; - - accessor.IsAccessLogEnabled = IsEnabledAccessLog(); - return Result.Success; - } - - public void Unmount(string mountName) - { - Result rc; - - if (IsEnabledAccessLog() && this.IsEnabledFileSystemAccessorAccessLog(mountName)) - { - TimeSpan startTime = Time.GetCurrent(); - - rc = MountTable.Unmount(mountName); - - TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\""); - } - else - { - rc = MountTable.Unmount(mountName); - } - - rc.ThrowIfFailure(); - } - - public void SetAccessLog(bool isEnabled, IAccessLog accessLog = null) - { - AccessLogEnabled = isEnabled; - - if (accessLog != null) AccessLog = accessLog; - } - - public Result CreateDirectory(string path) - { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.CreateDirectory(subPath.ToString()); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); - } - else - { - rc = fileSystem.CreateDirectory(subPath.ToString()); - } - - return rc; - } - - public Result CreateFile(string path, long size) - { - return CreateFile(path, size, CreateFileOptions.None); - } - - public Result CreateFile(string path, long size, CreateFileOptions options) - { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.CreateFile(subPath.ToString(), size, options); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\", size: {size}"); - } - else - { - rc = fileSystem.CreateFile(subPath.ToString(), size, options); - } - - return rc; - } - - public Result DeleteDirectory(string path) - { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.DeleteDirectory(subPath.ToString()); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); - } - else - { - rc = fileSystem.DeleteDirectory(subPath.ToString()); - } - - return rc; - } - - public Result DeleteDirectoryRecursively(string path) - { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); - } - else - { - rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); - } - - return rc; - } - - public Result CleanDirectoryRecursively(string path) - { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); - } - else - { - rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); - } - - return rc; - } - - public Result DeleteFile(string path) - { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.DeleteFile(subPath.ToString()); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); - } - else - { - rc = fileSystem.DeleteFile(subPath.ToString()); - } - - return rc; - } - - public Result RenameDirectory(string oldPath, string newPath) - { - Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); - if (rc.IsFailure()) return rc; - - rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); - if (rc.IsFailure()) return rc; - - if (oldFileSystem != newFileSystem) - { - return ResultFs.DifferentDestFileSystem.Log(); - } - - if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); - } - else - { - rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); - } - - return rc; - } - - public Result RenameFile(string oldPath, string newPath) - { - Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); - if (rc.IsFailure()) return rc; - - rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); - if (rc.IsFailure()) return rc; - - if (oldFileSystem != newFileSystem) - { - return ResultFs.DifferentDestFileSystem.Log(); - } - - if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); - } - else - { - rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); - } - - return rc; - } - - public Result GetEntryType(out DirectoryEntryType type, string path) - { - type = default; - - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.GetEntryType(out type, subPath.ToString()); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); - } - else - { - rc = fileSystem.GetEntryType(out type, subPath.ToString()); - } - - return rc; - } - - public Result OpenFile(out FileHandle handle, string path, OpenMode mode) - { - handle = default; - - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); - handle = new FileHandle(file); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); - } - else - { - rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); - handle = new FileHandle(file); - } - - return rc; - } - - public Result OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) - { - handle = default; - - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); - handle = new DirectoryHandle(dir); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); - } - else - { - rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); - handle = new DirectoryHandle(dir); - } - - return rc; - } - - public Result GetFreeSpaceSize(out long freeSpace, string path) - { - freeSpace = default; - - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - return fileSystem.GetFreeSpaceSize(out freeSpace, subPath.ToString()); - } - - public Result GetTotalSpaceSize(out long totalSpace, string path) - { - totalSpace = default; - - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - return fileSystem.GetTotalSpaceSize(out totalSpace, subPath.ToString()); - } - - public Result GetFileTimeStamp(out FileTimeStampRaw timeStamp, string path) - { - timeStamp = default; - - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); - if (rc.IsFailure()) return rc; - - return fileSystem.GetFileTimeStampRaw(out timeStamp, subPath.ToString()); - } - - public Result Commit(string mountName) - { - Result rc = MountTable.Find(mountName, out FileSystemAccessor fileSystem); - if (rc.IsFailure()) return rc; - - if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) - { - TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.Commit(); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\""); - } - else - { - rc = fileSystem.Commit(); - } - - return rc; - } - - // ========================== - // Operations on file handles - // ========================== - public Result ReadFile(FileHandle handle, long offset, Span destination) - { - return ReadFile(handle, offset, destination, ReadOption.None); - } - - public Result ReadFile(FileHandle handle, long offset, Span destination, ReadOption option) - { - Result rc = ReadFile(out long bytesRead, handle, offset, destination, option); - if (rc.IsFailure()) return rc; - - if (bytesRead == destination.Length) return Result.Success; - - return ResultFs.ValueOutOfRange.Log(); - } - - public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination) - { - return ReadFile(out bytesRead, handle, offset, destination, ReadOption.None); - } - - public Result ReadFile(out long bytesRead, FileHandle handle, long offset, Span destination, ReadOption option) - { - Result rc; - - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - rc = handle.File.Read(out bytesRead, offset, destination, option); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, handle, $", offset: {offset}, size: {destination.Length}"); - } - else - { - rc = handle.File.Read(out bytesRead, offset, destination, option); - } - - return rc; - } - - public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source) - { - return WriteFile(handle, offset, source, WriteOption.None); - } - - public Result WriteFile(FileHandle handle, long offset, ReadOnlySpan source, WriteOption option) - { - Result rc; - - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - rc = handle.File.Write(offset, source, option); - TimeSpan endTime = Time.GetCurrent(); - - string optionString = (option & WriteOption.Flush) == 0 ? "" : $", write_option: {option}"; - - OutputAccessLog(rc, startTime, endTime, handle, $", offset: {offset}, size: {source.Length}{optionString}"); - } - else - { - rc = handle.File.Write(offset, source, option); - } - - return rc; - } - - public Result FlushFile(FileHandle handle) - { - Result rc; - - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - rc = handle.File.Flush(); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, handle, string.Empty); - } - else - { - rc = handle.File.Flush(); - } - - return rc; - } - - public Result GetFileSize(out long fileSize, FileHandle handle) - { - return handle.File.GetSize(out fileSize); - } - - public Result SetFileSize(FileHandle handle, long size) - { - Result rc; - - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - rc = handle.File.SetSize(size); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, handle, $", size: {size}"); - } - else - { - rc = handle.File.SetSize(size); - } - - return rc; - } - - public OpenMode GetFileOpenMode(FileHandle handle) - { - return handle.File.OpenMode; - } - - public void CloseFile(FileHandle handle) - { - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - handle.File.Dispose(); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); - } - else - { - handle.File.Dispose(); - } - } - - // ========================== - // Operations on directory handles - // ========================== - public Result GetDirectoryEntryCount(out long count, DirectoryHandle handle) - { - return handle.Directory.GetEntryCount(out count); - } - - public Result ReadDirectory(out long entriesRead, Span entryBuffer, DirectoryHandle handle) - { - Result rc; - - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - rc = handle.Directory.Read(out entriesRead, entryBuffer); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, handle, string.Empty); - } - else - { - rc = handle.Directory.Read(out entriesRead, entryBuffer); - } - - return rc; - } - - public void CloseDirectory(DirectoryHandle handle) - { - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - handle.Directory.Dispose(); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); - } - else - { - handle.Directory.Dispose(); - } - } - - internal Result FindFileSystem(ReadOnlySpan path, out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - { - fileSystem = default; - - Result rc = GetMountName(path, out ReadOnlySpan mountName, out subPath); - if (rc.IsFailure()) return rc; - - rc = MountTable.Find(mountName.ToString(), out fileSystem); - if (rc.IsFailure()) return rc; - - return Result.Success; - } - - internal static Result GetMountName(ReadOnlySpan path, out ReadOnlySpan mountName, out ReadOnlySpan subPath) - { - int mountLen = 0; - int maxMountLen = Math.Min(path.Length, PathTools.MountNameLength); - - for (int i = 0; i < maxMountLen; i++) - { - if (path[i] == PathTools.MountSeparator) - { - mountLen = i; - break; - } - } - - if (mountLen == 0) - { - mountName = default; - subPath = default; - - return ResultFs.InvalidMountName; - } - - mountName = path.Slice(0, mountLen); - - if (mountLen + 1 < path.Length) - { - subPath = path.Slice(mountLen + 1); - } - else - { - subPath = default; - } - - return Result.Success; - } - - internal bool IsEnabledAccessLog() - { - return AccessLogEnabled && AccessLog != null && Time != null; - } - - internal bool IsEnabledHandleAccessLog(FileHandle handle) - { - return handle.File.Parent.IsAccessLogEnabled; - } - - internal bool IsEnabledHandleAccessLog(DirectoryHandle handle) - { - return handle.Directory.Parent.IsAccessLogEnabled; - } - - internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "") - { - AccessLog.Log(result, startTime, endTime, 0, message, caller); - } - - internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "") - { - AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller); - } - - internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "") - { - AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller); - } - } -} diff --git a/src/LibHac/Horizon.cs b/src/LibHac/Horizon.cs index cd9da365..d93fc1df 100644 --- a/src/LibHac/Horizon.cs +++ b/src/LibHac/Horizon.cs @@ -8,21 +8,16 @@ namespace LibHac { internal ITimeSpanGenerator Time { get; } - public FileSystemManager Fs { get; } + public FileSystemClient Fs { get; } public FileSystemServer FsSrv { get; private set; } private readonly object _initLocker = new object(); - public Horizon() - { - Fs = new FileSystemManager(this); - } - public Horizon(ITimeSpanGenerator timer) { Time = timer; - Fs = new FileSystemManager(this, timer); + Fs = new FileSystemClient(timer); } public void InitializeFileSystemServer(FileSystemCreators fsCreators) diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index 05cfaa33..e7d06748 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -8,7 +8,7 @@ namespace hactoolnet { public static class FsUtils { - public static void CopyDirectoryWithProgress(FileSystemManager fs, string sourcePath, string destPath, + public static void CopyDirectoryWithProgress(FileSystemClient fs, string sourcePath, string destPath, CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null) { try @@ -23,7 +23,7 @@ namespace hactoolnet } } - private static void CopyDirectoryWithProgressInternal(FileSystemManager fs, string sourcePath, string destPath, + private static void CopyDirectoryWithProgressInternal(FileSystemClient fs, string sourcePath, string destPath, CreateFileOptions options, IProgressReport logger) { fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All).ThrowIfFailure(); @@ -53,7 +53,7 @@ namespace hactoolnet } } - public static long GetTotalSize(FileSystemManager fs, string path, string searchPattern = "*") + public static long GetTotalSize(FileSystemClient fs, string path, string searchPattern = "*") { long size = 0; @@ -65,7 +65,7 @@ namespace hactoolnet return size; } - public static Result CopyFileWithProgress(FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) + public static Result CopyFileWithProgress(FileSystemClient fs, string sourcePath, string destPath, IProgressReport logger = null) { Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read); if (rc.IsFailure()) return rc; @@ -95,7 +95,7 @@ namespace hactoolnet rc = fs.ReadFile(out long _, sourceHandle, offset, buf); if (rc.IsFailure()) return rc; - rc = fs.WriteFile(destHandle, buf, offset); + rc = fs.WriteFile(destHandle, offset, buf); if (rc.IsFailure()) return rc; logger?.ReportAdd(toRead); diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index 311b14a1..dc640f5d 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -44,7 +44,7 @@ namespace hactoolnet if (ctx.Options.SectionOutDir[i] != null) { - FileSystemManager fs = ctx.Horizon.Fs; + FileSystemClient fs = ctx.Horizon.Fs; string mountName = $"section{i}"; @@ -95,7 +95,7 @@ namespace hactoolnet if (ctx.Options.RomfsOutDir != null) { - FileSystemManager fs = ctx.Horizon.Fs; + FileSystemClient fs = ctx.Horizon.Fs; fs.Register("rom".AsU8Span(), OpenFileSystemByType(NcaSectionType.Data)); fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir)); @@ -152,7 +152,7 @@ namespace hactoolnet if (ctx.Options.ExefsOutDir != null) { - FileSystemManager fs = ctx.Horizon.Fs; + FileSystemClient fs = ctx.Horizon.Fs; fs.Register("code".AsU8Span(), OpenFileSystemByType(NcaSectionType.Code)); fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir)); diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index 4f067a7c..a225d382 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -29,7 +29,7 @@ namespace hactoolnet bool signNeeded = ctx.Options.SignSave; var save = new SaveDataFileSystem(ctx.Keyset, file, ctx.Options.IntegrityLevel, true); - FileSystemManager fs = ctx.Horizon.Fs; + FileSystemClient fs = ctx.Horizon.Fs; fs.Register("save".AsU8Span(), save); From 838bb18a09b4cd8d2264d7a5ce1b885d1760f7dc Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 27 Sep 2019 23:36:43 -0500 Subject: [PATCH 30/46] 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 } } From 22bbf07c2bada743919f2ed5b8d626a4b911e2cd Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 29 Sep 2019 11:54:34 -0500 Subject: [PATCH 31/46] Add a function for handling possible access log output --- src/LibHac/Fs/FileSystemClient.AccessLog.cs | 23 ++++- src/LibHac/Fs/FileSystemClient.cs | 5 + src/LibHac/Fs/SaveData.cs | 101 ++++++-------------- src/LibHac/FsService/FileSystemProxy.cs | 6 +- src/LibHac/FsService/FileSystemProxyCore.cs | 14 +++ 5 files changed, 75 insertions(+), 74 deletions(-) diff --git a/src/LibHac/Fs/FileSystemClient.AccessLog.cs b/src/LibHac/Fs/FileSystemClient.AccessLog.cs index 926f4cff..f291ba80 100644 --- a/src/LibHac/Fs/FileSystemClient.AccessLog.cs +++ b/src/LibHac/Fs/FileSystemClient.AccessLog.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using LibHac.FsService; namespace LibHac.Fs @@ -32,7 +33,7 @@ namespace LibHac.Fs internal bool IsEnabledAccessLog(LocalAccessLogMode mode) { - if (!LocalAccessLogMode.HasFlag(mode)) + if ((LocalAccessLogMode & mode) == 0) { return false; } @@ -72,6 +73,26 @@ namespace LibHac.Fs { } + + public Result RunOperationWithAccessLog(LocalAccessLogMode logType, Func operation, Func textGenerator, [CallerMemberName] string caller = "") + { + Result rc; + + if (IsEnabledAccessLog(logType)) + { + TimeSpan startTime = Time.GetCurrent(); + rc = operation(); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, textGenerator(), caller); + } + else + { + rc = operation(); + } + + return rc; + } } [Flags] diff --git a/src/LibHac/Fs/FileSystemClient.cs b/src/LibHac/Fs/FileSystemClient.cs index 8ac67876..391e40ea 100644 --- a/src/LibHac/Fs/FileSystemClient.cs +++ b/src/LibHac/Fs/FileSystemClient.cs @@ -91,6 +91,11 @@ namespace LibHac.Fs { AccessLogEnabled = isEnabled; + if (isEnabled && FsSrv != null) + { + SetGlobalAccessLogMode(GlobalAccessLogMode.All); + } + if (accessLog != null) AccessLog = accessLog; } diff --git a/src/LibHac/Fs/SaveData.cs b/src/LibHac/Fs/SaveData.cs index 414ca00a..c9f0c4b4 100644 --- a/src/LibHac/Fs/SaveData.cs +++ b/src/LibHac/Fs/SaveData.cs @@ -1,5 +1,4 @@ -using System; -using LibHac.Common; +using LibHac.Common; using LibHac.FsService; namespace LibHac.Fs @@ -24,62 +23,33 @@ namespace LibHac.Fs 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) + 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 + return fs.RunOperationWithAccessLog(LocalAccessLogMode.Internal, + () => { - UserId = userId, - SaveDataId = saveDataId - }; + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); - var createInfo = new SaveDataCreateInfo - { - Size = size, - JournalSize = journalSize, - BlockSize = 0x4000, - OwnerId = ownerId, - Flags = flags, - SpaceId = spaceId - }; + var attribute = new SaveDataAttribute + { + UserId = userId, + SaveDataId = saveDataId + }; - Result rc = fsProxy.CreateSaveDataFileSystemBySystemSaveDataId(ref attribute, ref createInfo); + var createInfo = new SaveDataCreateInfo + { + Size = size, + JournalSize = journalSize, + BlockSize = 0x4000, + OwnerId = ownerId, + Flags = flags, + SpaceId = spaceId + }; - 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); - } + return fsProxy.CreateSaveDataFileSystemBySystemSaveDataId(ref attribute, ref createInfo); + }, + () => $", 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}"); } public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, UserId userId, @@ -114,24 +84,13 @@ namespace LibHac.Fs 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); - } + return fs.RunOperationWithAccessLog(LocalAccessLogMode.Internal, + () => + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + return fsProxy.DeleteSaveDataFileSystem(saveDataId); + }, + () => $", savedataid: 0x{saveDataId:X}"); } public static Result DisableAutoSaveDataCreation(this FileSystemClient fsClient) diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index 51fd4e0b..f4b8747f 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -522,12 +522,14 @@ namespace LibHac.FsService public Result SetGlobalAccessLogMode(GlobalAccessLogMode mode) { - throw new NotImplementedException(); + // Missing permission check + + return FsProxyCore.SetGlobalAccessLogMode(mode); } public Result GetGlobalAccessLogMode(out GlobalAccessLogMode mode) { - throw new NotImplementedException(); + return FsProxyCore.GetGlobalAccessLogMode(out mode); } public Result GetProgramIndexForAccessLog(out int programIndex, out int programCount) diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 7f30413f..b3df317f 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -14,6 +14,8 @@ namespace LibHac.FsService private const string NintendoDirectoryName = "Nintendo"; private const string ContentDirectoryName = "Contents"; + private GlobalAccessLogMode LogMode { get; set; } + public FileSystemProxyCore(FileSystemCreators fsCreators) { FsCreators = fsCreators; @@ -243,6 +245,18 @@ namespace LibHac.FsService } } + public Result SetGlobalAccessLogMode(GlobalAccessLogMode mode) + { + LogMode = mode; + return Result.Success; + } + + public Result GetGlobalAccessLogMode(out GlobalAccessLogMode mode) + { + mode = LogMode; + return Result.Success; + } + private string GetSaveDataIdPath(ulong saveDataId) { return $"/{saveDataId:x16}"; From 5011a57d3eea1b69c59f6cd0342e43042e87bd9a Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 30 Sep 2019 16:15:31 -0500 Subject: [PATCH 32/46] Add an option to control which types of access events are logged --- src/LibHac/Common/U8StringHelpers.cs | 4 +- src/LibHac/Fs/AccessLogHelpers.cs | 14 +++ src/LibHac/Fs/FileSystemClient.AccessLog.cs | 129 ++++++++++++++++++-- src/LibHac/Fs/FileSystemClient.File.cs | 57 ++------- src/LibHac/Fs/FileSystemClient.cs | 65 ++-------- src/hactoolnet/AccessLog.cs | 15 +-- src/hactoolnet/ProcessNca.cs | 12 +- src/hactoolnet/ProcessSave.cs | 6 +- src/hactoolnet/Program.cs | 7 +- 9 files changed, 172 insertions(+), 137 deletions(-) create mode 100644 src/LibHac/Fs/AccessLogHelpers.cs diff --git a/src/LibHac/Common/U8StringHelpers.cs b/src/LibHac/Common/U8StringHelpers.cs index 003b61fb..5dcae1ce 100644 --- a/src/LibHac/Common/U8StringHelpers.cs +++ b/src/LibHac/Common/U8StringHelpers.cs @@ -2,12 +2,12 @@ { public static class U8StringHelpers { - public static U8String AsU8String(this string value) + public static U8String ToU8String(this string value) { return new U8String(value); } - public static U8Span AsU8Span(this string value) + public static U8Span ToU8Span(this string value) { return new U8Span(value); } diff --git a/src/LibHac/Fs/AccessLogHelpers.cs b/src/LibHac/Fs/AccessLogHelpers.cs new file mode 100644 index 00000000..7fd00695 --- /dev/null +++ b/src/LibHac/Fs/AccessLogHelpers.cs @@ -0,0 +1,14 @@ +using System; + +namespace LibHac.Fs +{ + public static class AccessLogHelpers + { + public static string BuildDefaultLogLine(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, + string message, string caller) + { + return + $"FS_ACCESS: {{ start: {(long) startTime.TotalMilliseconds,9}, end: {(long) endTime.TotalMilliseconds,9}, result: 0x{result.Value:x8}, handle: 0x{handleId:x8}, function: \"{caller}\"{message} }}"; + } + } +} diff --git a/src/LibHac/Fs/FileSystemClient.AccessLog.cs b/src/LibHac/Fs/FileSystemClient.AccessLog.cs index f291ba80..0df0f797 100644 --- a/src/LibHac/Fs/FileSystemClient.AccessLog.cs +++ b/src/LibHac/Fs/FileSystemClient.AccessLog.cs @@ -1,5 +1,7 @@ using System; using System.Runtime.CompilerServices; +using LibHac.Common; +using LibHac.Fs.Accessors; using LibHac.FsService; namespace LibHac.Fs @@ -14,16 +16,28 @@ namespace LibHac.Fs public Result GetGlobalAccessLogMode(out GlobalAccessLogMode mode) { - IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); + if (HasFileSystemServer()) + { + IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); - return fsProxy.GetGlobalAccessLogMode(out mode); + return fsProxy.GetGlobalAccessLogMode(out mode); + } + + mode = GlobalAccessLogMode; + return Result.Success; } public Result SetGlobalAccessLogMode(GlobalAccessLogMode mode) { - IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); + if (HasFileSystemServer()) + { + IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); - return fsProxy.SetGlobalAccessLogMode(mode); + return fsProxy.SetGlobalAccessLogMode(mode); + } + + GlobalAccessLogMode = mode; + return Result.Success; } public void SetLocalAccessLogMode(LocalAccessLogMode mode) @@ -31,6 +45,11 @@ namespace LibHac.Fs LocalAccessLogMode = mode; } + public void SetAccessLogObject(IAccessLog accessLog) + { + AccessLog = accessLog; + } + internal bool IsEnabledAccessLog(LocalAccessLogMode mode) { if ((LocalAccessLogMode & mode) == 0) @@ -47,14 +66,21 @@ namespace LibHac.Fs { if (!AccessLogInitialized) { - IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); - - Result rc = fsProxy.GetGlobalAccessLogMode(out GlobalAccessLogMode globalMode); - GlobalAccessLogMode = globalMode; - - if (rc.IsFailure()) + if (HasFileSystemServer()) { - throw new LibHacException("Abort"); + IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); + + Result rc = fsProxy.GetGlobalAccessLogMode(out GlobalAccessLogMode globalMode); + GlobalAccessLogMode = globalMode; + + if (rc.IsFailure()) + { + throw new LibHacException("Abort"); + } + } + else + { + GlobalAccessLogMode = GlobalAccessLogMode.Log; } if (GlobalAccessLogMode != GlobalAccessLogMode.None) @@ -74,7 +100,65 @@ namespace LibHac.Fs } - public Result RunOperationWithAccessLog(LocalAccessLogMode logType, Func operation, Func textGenerator, [CallerMemberName] string caller = "") + internal bool IsEnabledAccessLog() + { + return IsEnabledAccessLog(LocalAccessLogMode.All); + } + + internal bool IsEnabledFileSystemAccessorAccessLog(string mountName) + { + if (MountTable.Find(mountName, out FileSystemAccessor accessor).IsFailure()) + { + return true; + } + + return accessor.IsAccessLogEnabled; + } + + internal bool IsEnabledHandleAccessLog(FileHandle handle) + { + return handle.File.Parent.IsAccessLogEnabled; + } + + internal bool IsEnabledHandleAccessLog(DirectoryHandle handle) + { + return handle.Directory.Parent.IsAccessLogEnabled; + } + + internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "") + { + OutputAccessLogImpl(result, startTime, endTime, 0, message, caller); + } + + internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "") + { + OutputAccessLogImpl(result, startTime, endTime, handle.GetId(), message, caller); + } + + internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "") + { + OutputAccessLogImpl(result, startTime, endTime, handle.GetId(), message, caller); + } + + internal void OutputAccessLogImpl(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, + string message, [CallerMemberName] string caller = "") + { + if (GlobalAccessLogMode.HasFlag(GlobalAccessLogMode.Log)) + { + AccessLog?.Log(result, startTime, endTime, handleId, message, caller); + } + + if (GlobalAccessLogMode.HasFlag(GlobalAccessLogMode.SdCard)) + { + string logString = AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller); + + IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); + fsProxy.OutputAccessLogToSdCard(logString.ToU8Span()); + } + } + + public Result RunOperationWithAccessLog(LocalAccessLogMode logType, Func operation, + Func textGenerator, [CallerMemberName] string caller = "") { Result rc; @@ -93,6 +177,27 @@ namespace LibHac.Fs return rc; } + + public Result RunOperationWithAccessLog(LocalAccessLogMode logType, FileHandle handle, Func operation, + Func textGenerator, [CallerMemberName] string caller = "") + { + Result rc; + + if (IsEnabledAccessLog(logType) && handle.File.Parent.IsAccessLogEnabled) + { + TimeSpan startTime = Time.GetCurrent(); + rc = operation(); + TimeSpan endTime = Time.GetCurrent(); + + OutputAccessLog(rc, startTime, endTime, textGenerator(), caller); + } + else + { + rc = operation(); + } + + return rc; + } } [Flags] diff --git a/src/LibHac/Fs/FileSystemClient.File.cs b/src/LibHac/Fs/FileSystemClient.File.cs index 3e508426..aab0c161 100644 --- a/src/LibHac/Fs/FileSystemClient.File.cs +++ b/src/LibHac/Fs/FileSystemClient.File.cs @@ -73,22 +73,9 @@ namespace LibHac.Fs public Result FlushFile(FileHandle handle) { - Result rc; - - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - rc = handle.File.Flush(); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, handle, string.Empty); - } - else - { - rc = handle.File.Flush(); - } - - return rc; + return RunOperationWithAccessLog(LocalAccessLogMode.All, handle, + () => handle.File.Flush(), + () => string.Empty); } public Result GetFileSize(out long fileSize, FileHandle handle) @@ -98,22 +85,9 @@ namespace LibHac.Fs public Result SetFileSize(FileHandle handle, long size) { - Result rc; - - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - rc = handle.File.SetSize(size); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(rc, startTime, endTime, handle, $", size: {size}"); - } - else - { - rc = handle.File.SetSize(size); - } - - return rc; + return RunOperationWithAccessLog(LocalAccessLogMode.All, handle, + () => handle.File.SetSize(size), + () => $", size: {size}"); } public OpenMode GetFileOpenMode(FileHandle handle) @@ -123,18 +97,13 @@ namespace LibHac.Fs public void CloseFile(FileHandle handle) { - if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) - { - TimeSpan startTime = Time.GetCurrent(); - handle.File.Dispose(); - TimeSpan endTime = Time.GetCurrent(); - - OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty); - } - else - { - handle.File.Dispose(); - } + RunOperationWithAccessLog(LocalAccessLogMode.All, handle, + () => + { + handle.File.Dispose(); + return Result.Success; + }, + () => string.Empty); } } } diff --git a/src/LibHac/Fs/FileSystemClient.cs b/src/LibHac/Fs/FileSystemClient.cs index 391e40ea..d4957282 100644 --- a/src/LibHac/Fs/FileSystemClient.cs +++ b/src/LibHac/Fs/FileSystemClient.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; using LibHac.Common; using LibHac.Fs.Accessors; using LibHac.FsService; @@ -16,19 +15,23 @@ namespace LibHac.Fs internal ITimeSpanGenerator Time { get; } private IAccessLog AccessLog { get; set; } - private bool AccessLogEnabled { get; set; } internal MountTable MountTable { get; } = new MountTable(); public FileSystemClient(ITimeSpanGenerator timer) { - Time = timer; + Time = timer ?? new StopWatchTimeSpanGenerator(); } public FileSystemClient(FileSystemServer fsServer, ITimeSpanGenerator timer) { FsSrv = fsServer; - Time = timer; + Time = timer ?? new StopWatchTimeSpanGenerator(); + } + + public bool HasFileSystemServer() + { + return FsSrv != null; } public IFileSystemProxy GetFileSystemProxyServiceObject() @@ -39,7 +42,7 @@ namespace LibHac.Fs { if (FsProxy != null) return FsProxy; - if (FsSrv == null) + if (!HasFileSystemServer()) { throw new InvalidOperationException("Client was not initialized with a server object."); } @@ -87,18 +90,6 @@ namespace LibHac.Fs rc.ThrowIfFailure(); } - public void SetAccessLog(bool isEnabled, IAccessLog accessLog = null) - { - AccessLogEnabled = isEnabled; - - if (isEnabled && FsSrv != null) - { - SetGlobalAccessLogMode(GlobalAccessLogMode.All); - } - - if (accessLog != null) AccessLog = accessLog; - } - internal Result FindFileSystem(ReadOnlySpan path, out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) { fileSystem = default; @@ -147,45 +138,5 @@ namespace LibHac.Fs return Result.Success; } - - internal bool IsEnabledAccessLog() - { - return AccessLogEnabled && AccessLog != null && Time != null; - } - - internal bool IsEnabledFileSystemAccessorAccessLog(string mountName) - { - if (MountTable.Find(mountName, out FileSystemAccessor accessor).IsFailure()) - { - return true; - } - - return accessor.IsAccessLogEnabled; - } - - internal bool IsEnabledHandleAccessLog(FileHandle handle) - { - return handle.File.Parent.IsAccessLogEnabled; - } - - internal bool IsEnabledHandleAccessLog(DirectoryHandle handle) - { - return handle.Directory.Parent.IsAccessLogEnabled; - } - - internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "") - { - AccessLog.Log(result, startTime, endTime, 0, message, caller); - } - - internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "") - { - AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller); - } - - internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "") - { - AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller); - } } } diff --git a/src/hactoolnet/AccessLog.cs b/src/hactoolnet/AccessLog.cs index 789965c6..67ba128f 100644 --- a/src/hactoolnet/AccessLog.cs +++ b/src/hactoolnet/AccessLog.cs @@ -10,7 +10,7 @@ namespace hactoolnet { public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "") { - Console.WriteLine(CommonAccessLog.BuildLogLine(result, startTime, endTime, handleId, message, caller)); + Console.WriteLine(AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller)); } } @@ -24,7 +24,7 @@ namespace hactoolnet public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "") { - Logger.LogMessage(CommonAccessLog.BuildLogLine(result, startTime, endTime, handleId, message, caller)); + Logger.LogMessage(AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller)); } } @@ -39,16 +39,7 @@ namespace hactoolnet public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "") { - Logger.WriteLine(CommonAccessLog.BuildLogLine(result, startTime, endTime, handleId, message, caller)); - } - } - - public static class CommonAccessLog - { - public static string BuildLogLine(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, - string caller) - { - return $"FS_ACCESS: {{ start: {(long)startTime.TotalMilliseconds,9}, end: {(long)endTime.TotalMilliseconds,9}, result: 0x{result.Value:x8}, handle: 0x{handleId:x8}, function: \"{caller}\"{message} }}"; + Logger.WriteLine(AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller)); } } } diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index dc640f5d..f6125e29 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -48,8 +48,8 @@ namespace hactoolnet string mountName = $"section{i}"; - fs.Register(mountName.AsU8Span(), OpenFileSystem(i)); - fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.SectionOutDir[i])); + fs.Register(mountName.ToU8Span(), OpenFileSystem(i)); + fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.SectionOutDir[i])); FsUtils.CopyDirectoryWithProgress(fs, mountName + ":/", "output:/", logger: ctx.Logger); @@ -97,8 +97,8 @@ namespace hactoolnet { FileSystemClient fs = ctx.Horizon.Fs; - fs.Register("rom".AsU8Span(), OpenFileSystemByType(NcaSectionType.Data)); - fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir)); + fs.Register("rom".ToU8Span(), OpenFileSystemByType(NcaSectionType.Data)); + fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir)); FsUtils.CopyDirectoryWithProgress(fs, "rom:/", "output:/", logger: ctx.Logger); @@ -154,8 +154,8 @@ namespace hactoolnet { FileSystemClient fs = ctx.Horizon.Fs; - fs.Register("code".AsU8Span(), OpenFileSystemByType(NcaSectionType.Code)); - fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir)); + fs.Register("code".ToU8Span(), OpenFileSystemByType(NcaSectionType.Code)); + fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir)); FsUtils.CopyDirectoryWithProgress(fs, "code:/", "output:/", logger: ctx.Logger); diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index a225d382..1a18db38 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -31,7 +31,7 @@ namespace hactoolnet var save = new SaveDataFileSystem(ctx.Keyset, file, ctx.Options.IntegrityLevel, true); FileSystemClient fs = ctx.Horizon.Fs; - fs.Register("save".AsU8Span(), save); + fs.Register("save".ToU8Span(), save); if (ctx.Options.Validate) { @@ -40,7 +40,7 @@ namespace hactoolnet if (ctx.Options.OutDir != null) { - fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.OutDir)); + fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.OutDir)); FsUtils.CopyDirectoryWithProgress(fs, "save:/", "output:/", logger: ctx.Logger); @@ -86,7 +86,7 @@ namespace hactoolnet if (ctx.Options.RepackSource != null) { - fs.Register("input".AsU8Span(), new LocalFileSystem(ctx.Options.RepackSource)); + fs.Register("input".ToU8Span(), new LocalFileSystem(ctx.Options.RepackSource)); fs.CleanDirectoryRecursively("save:/"); fs.Commit("save"); diff --git a/src/hactoolnet/Program.cs b/src/hactoolnet/Program.cs index a1222357..84ed4fb8 100644 --- a/src/hactoolnet/Program.cs +++ b/src/hactoolnet/Program.cs @@ -2,6 +2,7 @@ using System.IO; using System.Text; using LibHac; +using LibHac.Fs; namespace hactoolnet { @@ -63,7 +64,11 @@ namespace hactoolnet { logWriter = new StreamWriter(ctx.Options.AccessLog); var accessLog = new TextWriterAccessLog(logWriter); - ctx.Horizon.Fs.SetAccessLog(true, accessLog); + + ctx.Horizon.Fs.SetLocalAccessLogMode(LocalAccessLogMode.All); + ctx.Horizon.Fs.SetGlobalAccessLogMode(GlobalAccessLogMode.Log); + + ctx.Horizon.Fs.SetAccessLogObject(accessLog); } OpenKeyset(ctx); From d7f3e94577bcc8d3129aa7ed84b6c60727d69127 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 1 Oct 2019 16:31:21 -0500 Subject: [PATCH 33/46] Add a basic SaveDataFileSystemCreator --- src/LibHac/Fs/FileSystemClient.AccessLog.cs | 2 +- src/LibHac/Fs/IAttributeFileSystem.cs | 5 +- src/LibHac/Fs/ResultFs.cs | 1 + src/LibHac/Fs/SaveData.cs | 11 ++- src/LibHac/Fs/UserId.cs | 2 + .../FsService/Creators/FileSystemCreators.cs | 1 + .../Creators/SaveDataFileSystemCreator.cs | 70 +++++++++++++++++++ src/LibHac/FsService/FileSystemProxy.cs | 2 +- .../FsSystem/ConcatenationFileSystem.cs | 24 +++---- .../FsSystem/DirectorySaveDataFileSystem.cs | 2 +- src/LibHac/FsSystem/FileSystemExtensions.cs | 12 +++- src/LibHac/FsSystem/LocalFileSystem.cs | 56 ++++++++++++--- src/LibHac/FsSystem/SubdirectoryFileSystem.cs | 64 ++++++++--------- 13 files changed, 188 insertions(+), 64 deletions(-) create mode 100644 src/LibHac/FsService/Creators/SaveDataFileSystemCreator.cs diff --git a/src/LibHac/Fs/FileSystemClient.AccessLog.cs b/src/LibHac/Fs/FileSystemClient.AccessLog.cs index 0df0f797..e4f3bee8 100644 --- a/src/LibHac/Fs/FileSystemClient.AccessLog.cs +++ b/src/LibHac/Fs/FileSystemClient.AccessLog.cs @@ -189,7 +189,7 @@ namespace LibHac.Fs rc = operation(); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, textGenerator(), caller); + OutputAccessLog(rc, startTime, endTime, handle, textGenerator(), caller); } else { diff --git a/src/LibHac/Fs/IAttributeFileSystem.cs b/src/LibHac/Fs/IAttributeFileSystem.cs index e5a4858d..676a266e 100644 --- a/src/LibHac/Fs/IAttributeFileSystem.cs +++ b/src/LibHac/Fs/IAttributeFileSystem.cs @@ -2,8 +2,9 @@ { public interface IAttributeFileSystem : IFileSystem { - NxFileAttributes GetFileAttributes(string path); - void SetFileAttributes(string path, NxFileAttributes attributes); + Result CreateDirectory(string path, NxFileAttributes archiveAttribute); + Result GetFileAttributes(string path, out NxFileAttributes attributes); + Result SetFileAttributes(string path, NxFileAttributes attributes); long GetFileSize(string path); } } diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index fcc8eb68..7d547155 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -27,6 +27,7 @@ public static Result InvalidIndirectStorageSource => new Result(ModuleFs, 4023); public static Result Result4302 => new Result(ModuleFs, 4302); + public static Result InvalidSaveDataEntryType => new Result(ModuleFs, 4303); public static Result InvalidSaveDataHeader => new Result(ModuleFs, 4315); public static Result Result4362 => new Result(ModuleFs, 4362); public static Result Result4363 => new Result(ModuleFs, 4363); diff --git a/src/LibHac/Fs/SaveData.cs b/src/LibHac/Fs/SaveData.cs index c9f0c4b4..09d98fb2 100644 --- a/src/LibHac/Fs/SaveData.cs +++ b/src/LibHac/Fs/SaveData.cs @@ -5,6 +5,11 @@ namespace LibHac.Fs { public static class SaveData { + public static Result MountSystemSaveData(this FileSystemClient fs, U8Span mountName, SaveDataSpaceId spaceId, ulong saveDataId) + { + return MountSystemSaveData(fs, mountName, spaceId, saveDataId, UserId.EmptyId); + } + public static Result MountSystemSaveData(this FileSystemClient fs, U8Span mountName, SaveDataSpaceId spaceId, ulong saveDataId, UserId userId) { @@ -67,19 +72,19 @@ namespace LibHac.Fs 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); + return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.EmptyId, 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); + return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.EmptyId, 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); + return CreateSystemSaveData(fs, spaceId, saveDataId, UserId.EmptyId, ownerId, size, journalSize, flags); } public static Result DeleteSaveData(this FileSystemClient fs, ulong saveDataId) diff --git a/src/LibHac/Fs/UserId.cs b/src/LibHac/Fs/UserId.cs index 4a14fc46..5d89fbcb 100644 --- a/src/LibHac/Fs/UserId.cs +++ b/src/LibHac/Fs/UserId.cs @@ -7,6 +7,8 @@ namespace LibHac.Fs [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct UserId : IEquatable, IComparable, IComparable { + public static readonly UserId EmptyId = new UserId(0, 0); + public readonly Id128 Id; public UserId(ulong high, ulong low) diff --git a/src/LibHac/FsService/Creators/FileSystemCreators.cs b/src/LibHac/FsService/Creators/FileSystemCreators.cs index 2afa63df..c0f83871 100644 --- a/src/LibHac/FsService/Creators/FileSystemCreators.cs +++ b/src/LibHac/FsService/Creators/FileSystemCreators.cs @@ -26,6 +26,7 @@ namespace LibHac.FsService.Creators var creators = new FileSystemCreators(); creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); + creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(keyset); creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keyset); creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem); creators.SdFileSystemCreator = new EmulatedSdFileSystemCreator(rootFileSystem); diff --git a/src/LibHac/FsService/Creators/SaveDataFileSystemCreator.cs b/src/LibHac/FsService/Creators/SaveDataFileSystemCreator.cs new file mode 100644 index 00000000..9574b70c --- /dev/null +++ b/src/LibHac/FsService/Creators/SaveDataFileSystemCreator.cs @@ -0,0 +1,70 @@ +using System; +using LibHac.Common; +using LibHac.Fs; +using LibHac.FsSystem; +using LibHac.FsSystem.Save; + +namespace LibHac.FsService.Creators +{ + public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator + { + private Keyset Keyset { get; } + + public SaveDataFileSystemCreator(Keyset keyset) + { + Keyset = keyset; + } + + public Result CreateFile(out IFile file, IFileSystem sourceFileSystem, ulong saveDataId, OpenMode openMode) + { + throw new NotImplementedException(); + } + + public Result Create(out IFileSystem fileSystem, out ISaveDataExtraDataAccessor extraDataAccessor, + IFileSystem sourceFileSystem, ulong saveDataId, bool allowDirectorySaveData, bool useDeviceUniqueMac, + SaveDataType type, ITimeStampGenerator timeStampGenerator) + { + fileSystem = default; + extraDataAccessor = default; + + string saveDataPath = $"/{saveDataId:x16}"; + + Result rc = sourceFileSystem.GetEntryType(out DirectoryEntryType entryType, saveDataPath); + if (rc.IsFailure()) + { + return rc == ResultFs.PathNotFound ? ResultFs.TargetNotFound : rc; + } + + switch (entryType) + { + case DirectoryEntryType.Directory: + if (!allowDirectorySaveData) return ResultFs.InvalidSaveDataEntryType.Log(); + + var subDirFs = new SubdirectoryFileSystem(sourceFileSystem, saveDataPath); + fileSystem = new DirectorySaveDataFileSystem(subDirFs); + + // Todo: Dummy ISaveDataExtraDataAccessor + + return Result.Success; + + case DirectoryEntryType.File: + rc = sourceFileSystem.OpenFile(out IFile saveDataFile, saveDataPath, OpenMode.ReadWrite); + if (rc.IsFailure()) return rc; + + var saveDataStorage = new FileStorage(saveDataFile); + fileSystem = new SaveDataFileSystem(Keyset, saveDataStorage, IntegrityCheckLevel.ErrorOnInvalid, true); + + // Todo: ISaveDataExtraDataAccessor + + return Result.Success; + default: + throw new ArgumentOutOfRangeException(); + } + } + + public void SetSdCardEncryptionSeed(ReadOnlySpan seed) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index f4b8747f..0202cd03 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -163,7 +163,7 @@ namespace LibHac.FsService if (saveFsResult.IsSuccess()) return Result.Success; - if (saveFsResult == ResultFs.PathNotFound || saveFsResult == ResultFs.TargetNotFound) return saveFsResult; + if (saveFsResult != ResultFs.PathNotFound && saveFsResult != ResultFs.TargetNotFound) return saveFsResult; if (saveDataId != SaveIndexerId) { diff --git a/src/LibHac/FsSystem/ConcatenationFileSystem.cs b/src/LibHac/FsSystem/ConcatenationFileSystem.cs index f9683629..5de0cf13 100644 --- a/src/LibHac/FsSystem/ConcatenationFileSystem.cs +++ b/src/LibHac/FsSystem/ConcatenationFileSystem.cs @@ -54,14 +54,20 @@ namespace LibHac.FsSystem #if CROSS_PLATFORM if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - return HasConcatenationFileAttribute(BaseFileSystem.GetFileAttributes(path)); + Result rc = BaseFileSystem.GetFileAttributes(path, out NxFileAttributes attributes); + if (rc.IsFailure()) return false; + + return HasConcatenationFileAttribute(attributes); } else { return IsConcatenationFileHeuristic(path); } #else - return HasConcatenationFileAttribute(BaseFileSystem.GetFileAttributes(path)); + Result rc = BaseFileSystem.GetFileAttributes(path, out NxFileAttributes attributes); + if (rc.IsFailure()) return false; + + return HasConcatenationFileAttribute(attributes); #endif } @@ -93,11 +99,9 @@ namespace LibHac.FsSystem return (attributes & NxFileAttributes.Directory) != 0 && (attributes & NxFileAttributes.Archive) != 0; } - private void SetConcatenationFileAttribute(string path) + private Result SetConcatenationFileAttribute(string path) { - NxFileAttributes attributes = BaseFileSystem.GetFileAttributes(path); - attributes |= NxFileAttributes.Archive; - BaseFileSystem.SetFileAttributes(path, attributes); + return BaseFileSystem.SetFileAttributes(path, NxFileAttributes.Archive); } public Result CreateDirectory(string path) @@ -134,11 +138,9 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - Result rc = BaseFileSystem.CreateDirectory(path); + Result rc = BaseFileSystem.CreateDirectory(path, NxFileAttributes.Archive); if (rc.IsFailure()) return rc; - SetConcatenationFileAttribute(path); - long remaining = size; for (int i = 0; remaining > 0; i++) @@ -320,9 +322,7 @@ namespace LibHac.FsSystem { if (queryId != QueryId.MakeConcatFile) return ResultFs.UnsupportedOperationInConcatFsQueryEntry.Log(); - SetConcatenationFileAttribute(path); - - return Result.Success; + return SetConcatenationFileAttribute(path); } private int GetSubFileCount(string dirPath) diff --git a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs index 361f6ce7..4a5838fa 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs @@ -213,7 +213,7 @@ namespace LibHac.FsSystem rc = BaseFs.CreateDirectory(dest); if (rc.IsFailure()) return rc; - return this.CopyDirectory(this, src, dest); + return BaseFs.CopyDirectory(BaseFs, src, dest); } internal void NotifyCloseWritableFile() diff --git a/src/LibHac/FsSystem/FileSystemExtensions.cs b/src/LibHac/FsSystem/FileSystemExtensions.cs index 1c89dd2c..cbe7478d 100644 --- a/src/LibHac/FsSystem/FileSystemExtensions.cs +++ b/src/LibHac/FsSystem/FileSystemExtensions.cs @@ -182,10 +182,18 @@ namespace LibHac.FsSystem return (NxFileAttributes)(((int)attributes >> 4) & 3); } + public static FileAttributes ToFatAttributes(this NxFileAttributes attributes) + { + return (FileAttributes)(((int)attributes & 3) << 4); + } + public static FileAttributes ApplyNxAttributes(this FileAttributes attributes, NxFileAttributes nxAttributes) { - var nxAttributeBits = (FileAttributes)(((int)nxAttributes & 3) << 4); - return attributes | nxAttributeBits; + // The only 2 bits from FileAttributes that are used in NxFileAttributes + const int mask = 3 << 4; + + FileAttributes oldAttributes = attributes & (FileAttributes)mask; + return oldAttributes | nxAttributes.ToFatAttributes(); } public static void SetConcatenationFileAttribute(this IFileSystem fs, string path) diff --git a/src/LibHac/FsSystem/LocalFileSystem.cs b/src/LibHac/FsSystem/LocalFileSystem.cs index 0e3431e5..13d39665 100644 --- a/src/LibHac/FsSystem/LocalFileSystem.cs +++ b/src/LibHac/FsSystem/LocalFileSystem.cs @@ -34,21 +34,46 @@ namespace LibHac.FsSystem return PathTools.Combine(BasePath, path); } - public NxFileAttributes GetFileAttributes(string path) + public Result GetFileAttributes(string path, out NxFileAttributes attributes) { - path = PathTools.Normalize(path); - return File.GetAttributes(ResolveLocalPath(path)).ToNxAttributes(); + string localPath = ResolveLocalPath(PathTools.Normalize(path)); + + FileInfo info = GetFileInfo(localPath); + + if (info.Attributes == (FileAttributes)(-1)) + { + attributes = default; + return ResultFs.PathNotFound.Log(); + } + + attributes = info.Attributes.ToNxAttributes(); + return Result.Success; } - public void SetFileAttributes(string path, NxFileAttributes attributes) + public Result SetFileAttributes(string path, NxFileAttributes attributes) { - path = PathTools.Normalize(path); - string localPath = ResolveLocalPath(path); + string localPath = ResolveLocalPath(PathTools.Normalize(path)); - FileAttributes attributesOld = File.GetAttributes(localPath); + FileInfo info = GetFileInfo(localPath); + + if (info.Attributes == (FileAttributes)(-1)) + { + return ResultFs.PathNotFound.Log(); + } + + FileAttributes attributesOld = info.Attributes; FileAttributes attributesNew = attributesOld.ApplyNxAttributes(attributes); - File.SetAttributes(localPath, attributesNew); + try + { + info.Attributes = attributesNew; + } + catch (IOException) + { + return ResultFs.PathNotFound.Log(); + } + + return Result.Success; } public long GetFileSize(string path) @@ -60,6 +85,11 @@ namespace LibHac.FsSystem } public Result CreateDirectory(string path) + { + return CreateDirectory(path, NxFileAttributes.None); + } + + public Result CreateDirectory(string path, NxFileAttributes archiveAttribute) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); @@ -75,7 +105,7 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - return CreateDirInternal(dir); + return CreateDirInternal(dir, archiveAttribute); } public Result CreateFile(string path, long size, CreateFileOptions options) @@ -394,11 +424,17 @@ namespace LibHac.FsSystem return Result.Success; } - private static Result CreateDirInternal(DirectoryInfo dir) + private static Result CreateDirInternal(DirectoryInfo dir, NxFileAttributes attributes) { try { dir.Create(); + dir.Refresh(); + + if (attributes.HasFlag(NxFileAttributes.Archive)) + { + dir.Attributes |= FileAttributes.Archive; + } } catch (DirectoryNotFoundException) { diff --git a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs index ad61357e..e9bb51f8 100644 --- a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs +++ b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs @@ -21,81 +21,81 @@ namespace LibHac.FsSystem public Result CreateDirectory(string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.CreateDirectory(ResolveFullPath(path)); + return ParentFileSystem.CreateDirectory(fullPath); } public Result CreateFile(string path, long size, CreateFileOptions options) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.CreateFile(ResolveFullPath(path), size, options); + return ParentFileSystem.CreateFile(fullPath, size, options); } public Result DeleteDirectory(string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.DeleteDirectory(ResolveFullPath(path)); + return ParentFileSystem.DeleteDirectory(fullPath); } public Result DeleteDirectoryRecursively(string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.DeleteDirectoryRecursively(ResolveFullPath(path)); + return ParentFileSystem.DeleteDirectoryRecursively(fullPath); } public Result CleanDirectoryRecursively(string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.CleanDirectoryRecursively(ResolveFullPath(path)); + return ParentFileSystem.CleanDirectoryRecursively(fullPath); } public Result DeleteFile(string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.DeleteFile(ResolveFullPath(path)); + return ParentFileSystem.DeleteFile(fullPath); } public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.OpenDirectory(out directory, ResolveFullPath(path), mode); + return ParentFileSystem.OpenDirectory(out directory, fullPath, mode); } public Result OpenFile(out IFile file, string path, OpenMode mode) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.OpenFile(out file, ResolveFullPath(path), mode); + return ParentFileSystem.OpenFile(out file, fullPath, mode); } public Result RenameDirectory(string oldPath, string newPath) { - oldPath = PathTools.Normalize(oldPath); - newPath = PathTools.Normalize(newPath); + string fullOldPath = ResolveFullPath(PathTools.Normalize(oldPath)); + string fullNewPath = ResolveFullPath(PathTools.Normalize(newPath)); - return ParentFileSystem.RenameDirectory(oldPath, newPath); + return ParentFileSystem.RenameDirectory(fullOldPath, fullNewPath); } public Result RenameFile(string oldPath, string newPath) { - oldPath = PathTools.Normalize(oldPath); - newPath = PathTools.Normalize(newPath); + string fullOldPath = ResolveFullPath(PathTools.Normalize(oldPath)); + string fullNewPath = ResolveFullPath(PathTools.Normalize(newPath)); - return ParentFileSystem.RenameFile(oldPath, newPath); + return ParentFileSystem.RenameFile(fullOldPath, fullNewPath); } public Result GetEntryType(out DirectoryEntryType entryType, string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.GetEntryType(out entryType, ResolveFullPath(path)); + return ParentFileSystem.GetEntryType(out entryType, fullPath); } public Result Commit() @@ -105,30 +105,30 @@ namespace LibHac.FsSystem public Result GetFreeSpaceSize(out long freeSpace, string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.GetFreeSpaceSize(out freeSpace, ResolveFullPath(path)); + return ParentFileSystem.GetFreeSpaceSize(out freeSpace, fullPath); } public Result GetTotalSpaceSize(out long totalSpace, string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.GetTotalSpaceSize(out totalSpace, ResolveFullPath(path)); + return ParentFileSystem.GetTotalSpaceSize(out totalSpace, fullPath); } public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.GetFileTimeStampRaw(out timeStamp, ResolveFullPath(path)); + return ParentFileSystem.GetFileTimeStampRaw(out timeStamp, fullPath); } public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - path = PathTools.Normalize(path); + string fullPath = ResolveFullPath(PathTools.Normalize(path)); - return ParentFileSystem.QueryEntry(outBuffer, inBuffer, queryId, ResolveFullPath(path)); + return ParentFileSystem.QueryEntry(outBuffer, inBuffer, queryId, fullPath); } } } From d291500b28bf48b163286ef0ee8a0d80480e5acf Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Wed, 2 Oct 2019 13:45:58 -0500 Subject: [PATCH 34/46] Add ExternalKeySet. Use C# 8.0 --- src/LibHac/Common/Id128.cs | 42 +++------ src/LibHac/Common/Key128.cs | 48 +++++++++++ src/LibHac/Fs/FileBase.cs | 2 +- src/LibHac/Fs/ResultFs.cs | 11 ++- src/LibHac/Fs/RightsId.cs | 19 ++++- src/LibHac/Fs/SaveData.cs | 8 +- src/LibHac/Fs/UserId.cs | 16 +++- src/LibHac/FsService/ExternalKeySet.cs | 108 ++++++++++++++++++++++++ src/LibHac/FsService/FileSystemProxy.cs | 2 +- src/LibHac/FsSystem/NcaUtils/Nca.cs | 8 +- src/LibHac/Keyset.cs | 12 ++- src/LibHac/LibHac.csproj | 2 +- src/LibHac/Ncm/ContentId.cs | 11 ++- src/LibHac/Ncm/PlaceHolderId.cs | 11 ++- src/LibHac/Spl/AccessKey.cs | 21 +++-- src/LibHac/Util.cs | 4 +- 16 files changed, 266 insertions(+), 59 deletions(-) create mode 100644 src/LibHac/Common/Key128.cs create mode 100644 src/LibHac/FsService/ExternalKeySet.cs diff --git a/src/LibHac/Common/Id128.cs b/src/LibHac/Common/Id128.cs index a0289014..2cb598e6 100644 --- a/src/LibHac/Common/Id128.cs +++ b/src/LibHac/Common/Id128.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; namespace LibHac.Common @@ -6,13 +7,14 @@ namespace LibHac.Common /// /// A generic 128-bit ID value. /// + [DebuggerDisplay("{ToString()}")] [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct Id128 : IEquatable, IComparable, IComparable { public readonly ulong High; public readonly ulong Low; - public static readonly Id128 InvalidId = new Id128(0, 0); + public static Id128 Zero => default; public Id128(ulong high, ulong low) { @@ -28,6 +30,8 @@ namespace LibHac.Common Low = longs[1]; } + public override string ToString() => AsBytes().ToHexString(); + public bool Equals(Id128 other) { return High == other.High && Low == other.Low; @@ -48,11 +52,9 @@ namespace LibHac.Common public int CompareTo(Id128 other) { - // ReSharper disable ImpureMethodCallOnReadonlyValueField int highComparison = High.CompareTo(other.High); if (highComparison != 0) return highComparison; return Low.CompareTo(other.Low); - // ReSharper restore ImpureMethodCallOnReadonlyValueField } public int CompareTo(object obj) @@ -61,7 +63,7 @@ namespace LibHac.Common return obj is Id128 other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(Id128)}"); } - public void ToBytes(Span output) + public readonly void ToBytes(Span output) { Span longs = MemoryMarshal.Cast(output); @@ -69,33 +71,17 @@ namespace LibHac.Common longs[1] = Low; } - public static bool operator ==(Id128 left, Id128 right) + public ReadOnlySpan AsBytes() { - return left.Equals(right); + return SpanHelpers.AsByteSpan(ref this); } - public static bool operator !=(Id128 left, Id128 right) - { - return !left.Equals(right); - } - public static bool operator <(Id128 left, Id128 right) - { - return left.CompareTo(right) < 0; - } + public static bool operator ==(Id128 left, Id128 right) => left.Equals(right); + public static bool operator !=(Id128 left, Id128 right) => !left.Equals(right); - public static bool operator >(Id128 left, Id128 right) - { - return left.CompareTo(right) > 0; - } - - public static bool operator <=(Id128 left, Id128 right) - { - return left.CompareTo(right) <= 0; - } - - public static bool operator >=(Id128 left, Id128 right) - { - return left.CompareTo(right) >= 0; - } + public static bool operator <(Id128 left, Id128 right) => left.CompareTo(right) < 0; + public static bool operator >(Id128 left, Id128 right) => left.CompareTo(right) > 0; + public static bool operator <=(Id128 left, Id128 right) => left.CompareTo(right) <= 0; + public static bool operator >=(Id128 left, Id128 right) => left.CompareTo(right) >= 0; } } diff --git a/src/LibHac/Common/Key128.cs b/src/LibHac/Common/Key128.cs new file mode 100644 index 00000000..6febda1a --- /dev/null +++ b/src/LibHac/Common/Key128.cs @@ -0,0 +1,48 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace LibHac.Common +{ + [DebuggerDisplay("{ToString()}")] + [StructLayout(LayoutKind.Sequential, Size = 0x10)] + public struct Key128 : IEquatable + { + private readonly ulong _dummy1; + private readonly ulong _dummy2; + + public Span Value => SpanHelpers.AsByteSpan(ref this); + + public Key128(ReadOnlySpan bytes) + { + ReadOnlySpan longs = MemoryMarshal.Cast(bytes); + + _dummy1 = longs[0]; + _dummy2 = longs[1]; + } + + public override string ToString() => Value.ToHexString(); + + public override bool Equals(object obj) + { + return obj is Key128 key && Equals(key); + } + + public bool Equals(Key128 other) + { + return _dummy1 == other._dummy1 && + _dummy2 == other._dummy2; + } + + public override int GetHashCode() + { + int hashCode = -1653217991; + hashCode = hashCode * -1521134295 + _dummy1.GetHashCode(); + hashCode = hashCode * -1521134295 + _dummy2.GetHashCode(); + return hashCode; + } + + public static bool operator ==(Key128 left, Key128 right) => left.Equals(right); + public static bool operator !=(Key128 left, Key128 right) => !(left == right); + } +} diff --git a/src/LibHac/Fs/FileBase.cs b/src/LibHac/Fs/FileBase.cs index 5caa7829..244c8200 100644 --- a/src/LibHac/Fs/FileBase.cs +++ b/src/LibHac/Fs/FileBase.cs @@ -121,7 +121,7 @@ namespace LibHac.Fs if (!openMode.HasFlag(OpenMode.AllowAppend)) { - return ResultFs.AllowAppendRequiredForImplicitExtension.Log(); + return ResultFs.FileExtensionWithoutOpenModeAllowAppend.Log(); } } diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 7d547155..b9d4edfe 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -11,7 +11,9 @@ public static Result InsufficientFreeSpace => new Result(ModuleFs, 30); public static Result MountNameAlreadyExists => new Result(ModuleFs, 60); + public static Result PartitionNotFound => new Result(ModuleFs, 1001); public static Result TargetNotFound => new Result(ModuleFs, 1002); + public static Result ExternalKeyNotFound => new Result(ModuleFs, 1004); public static Result NotImplemented => new Result(ModuleFs, 3001); public static Result Result3002 => new Result(ModuleFs, 3002); @@ -80,9 +82,11 @@ public static Result InvalidSize => new Result(ModuleFs, 6062); public static Result NullArgument => new Result(ModuleFs, 6063); public static Result InvalidMountName => new Result(ModuleFs, 6065); + public static Result ExtensionSizeTooLarge => new Result(ModuleFs, 6066); + public static Result ExtensionSizeInvalid => new Result(ModuleFs, 6067); public static Result InvalidOpenModeOperation => new Result(ModuleFs, 6200); - public static Result AllowAppendRequiredForImplicitExtension => new Result(ModuleFs, 6201); + public static Result FileExtensionWithoutOpenModeAllowAppend => new Result(ModuleFs, 6201); public static Result InvalidOpenModeForRead => new Result(ModuleFs, 6202); public static Result InvalidOpenModeForWrite => new Result(ModuleFs, 6203); @@ -105,11 +109,16 @@ public static Result UnsupportedOperationInPartitionFileSetSize => new Result(ModuleFs, 6376); public static Result PermissionDenied => new Result(ModuleFs, 6400); + public static Result ExternalKeyAlreadyRegistered => new Result(ModuleFs, 6452); public static Result WriteStateUnflushed => new Result(ModuleFs, 6454); public static Result WritableFileOpen => new Result(ModuleFs, 6457); + public static Result MappingTableFull => new Result(ModuleFs, 6706); public static Result AllocationTableInsufficientFreeBlocks => new Result(ModuleFs, 6707); + public static Result OpenCountLimit => new Result(ModuleFs, 6709); + + public static Result RemapStorageMapFull => new Result(ModuleFs, 6811); public static Result Result6902 => new Result(ModuleFs, 6902); public static Result MountNameNotFound => new Result(ModuleFs, 6905); diff --git a/src/LibHac/Fs/RightsId.cs b/src/LibHac/Fs/RightsId.cs index 11f0969d..120eec89 100644 --- a/src/LibHac/Fs/RightsId.cs +++ b/src/LibHac/Fs/RightsId.cs @@ -1,9 +1,11 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; using LibHac.Common; namespace LibHac.Fs { + [DebuggerDisplay("{DebugDisplay(),nq}")] [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct RightsId : IEquatable, IComparable, IComparable { @@ -19,12 +21,21 @@ namespace LibHac.Fs Id = new Id128(uid); } + public override string ToString() => Id.ToString(); + + public string DebugDisplay() + { + ReadOnlySpan highBytes = AsBytes().Slice(0, 8); + ReadOnlySpan lowBytes = AsBytes().Slice(8, 8); + + return $"{highBytes.ToHexString()} {lowBytes.ToHexString()}"; + } + public bool Equals(RightsId other) => Id == other.Id; public override bool Equals(object obj) => obj is RightsId other && Equals(other); public override int GetHashCode() => Id.GetHashCode(); - // ReSharper disable once ImpureMethodCallOnReadonlyValueField public int CompareTo(RightsId other) => Id.CompareTo(other.Id); public int CompareTo(object obj) @@ -33,9 +44,13 @@ namespace LibHac.Fs return obj is RightsId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(RightsId)}"); } - // ReSharper disable once ImpureMethodCallOnReadonlyValueField public void ToBytes(Span output) => Id.ToBytes(output); + public ReadOnlySpan AsBytes() + { + return SpanHelpers.AsByteSpan(ref this); + } + public static bool operator ==(RightsId left, RightsId right) => left.Equals(right); public static bool operator !=(RightsId left, RightsId right) => !left.Equals(right); diff --git a/src/LibHac/Fs/SaveData.cs b/src/LibHac/Fs/SaveData.cs index 09d98fb2..5ae9468d 100644 --- a/src/LibHac/Fs/SaveData.cs +++ b/src/LibHac/Fs/SaveData.cs @@ -7,7 +7,7 @@ namespace LibHac.Fs { public static Result MountSystemSaveData(this FileSystemClient fs, U8Span mountName, SaveDataSpaceId spaceId, ulong saveDataId) { - return MountSystemSaveData(fs, mountName, spaceId, saveDataId, UserId.EmptyId); + return MountSystemSaveData(fs, mountName, spaceId, saveDataId, UserId.Zero); } public static Result MountSystemSaveData(this FileSystemClient fs, U8Span mountName, @@ -72,19 +72,19 @@ namespace LibHac.Fs public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, ulong ownerId, long size, long journalSize, uint flags) { - return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.EmptyId, ownerId, size, journalSize, flags); + return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.Zero, 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, UserId.EmptyId, 0, size, journalSize, flags); + return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.Zero, 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, UserId.EmptyId, ownerId, size, journalSize, flags); + return CreateSystemSaveData(fs, spaceId, saveDataId, UserId.Zero, ownerId, size, journalSize, flags); } public static Result DeleteSaveData(this FileSystemClient fs, ulong saveDataId) diff --git a/src/LibHac/Fs/UserId.cs b/src/LibHac/Fs/UserId.cs index 5d89fbcb..31db1dec 100644 --- a/src/LibHac/Fs/UserId.cs +++ b/src/LibHac/Fs/UserId.cs @@ -1,13 +1,15 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; using LibHac.Common; namespace LibHac.Fs { + [DebuggerDisplay("{ToString(),nq}")] [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct UserId : IEquatable, IComparable, IComparable { - public static readonly UserId EmptyId = new UserId(0, 0); + public static UserId Zero => default; public readonly Id128 Id; @@ -21,12 +23,16 @@ namespace LibHac.Fs Id = new Id128(uid); } + public override string ToString() + { + return $"0x{Id.High:x8}{Id.Low:x8}"; + } + public bool Equals(UserId other) => Id == other.Id; public override bool Equals(object obj) => obj is UserId other && Equals(other); public override int GetHashCode() => Id.GetHashCode(); - // ReSharper disable once ImpureMethodCallOnReadonlyValueField public int CompareTo(UserId other) => Id.CompareTo(other.Id); public int CompareTo(object obj) @@ -35,9 +41,13 @@ namespace LibHac.Fs return obj is UserId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(UserId)}"); } - // ReSharper disable once ImpureMethodCallOnReadonlyValueField public void ToBytes(Span output) => Id.ToBytes(output); + public ReadOnlySpan AsBytes() + { + return SpanHelpers.AsByteSpan(ref this); + } + public static bool operator ==(UserId left, UserId right) => left.Equals(right); public static bool operator !=(UserId left, UserId right) => !left.Equals(right); diff --git a/src/LibHac/FsService/ExternalKeySet.cs b/src/LibHac/FsService/ExternalKeySet.cs new file mode 100644 index 00000000..dd6172ec --- /dev/null +++ b/src/LibHac/FsService/ExternalKeySet.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using LibHac.Fs; +using LibHac.Spl; + +namespace LibHac.FsService +{ + public class ExternalKeySet + { + private readonly object _locker = new object(); + + private Dictionary ExternalKeys { get; set; } = new Dictionary(); + + public Result Add(RightsId rightsId, AccessKey key) + { + lock (_locker) + { + if (ExternalKeys.TryGetValue(rightsId, out AccessKey existingKey)) + { + if (key == existingKey) + { + return Result.Success; + } + + return ResultFs.ExternalKeyAlreadyRegistered.Log(); + } + + ExternalKeys.Add(rightsId, key); + } + + return Result.Success; + } + + public Result Get(RightsId rightsId, out AccessKey key) + { + lock (_locker) + { + if (ExternalKeys.TryGetValue(rightsId, out key)) + { + return Result.Success; + } + + return ResultFs.ExternalKeyNotFound.Log(); + } + } + + public bool Contains(RightsId rightsId) + { + lock (_locker) + { + return ExternalKeys.ContainsKey(rightsId); + } + } + + public bool Remove(RightsId rightsId) + { + lock (_locker) + { + return ExternalKeys.Remove(rightsId); + } + } + + public void Clear() + { + lock (_locker) + { + ExternalKeys.Clear(); + } + } + + public List<(RightsId rightsId, AccessKey key)> ToList() + { + lock (_locker) + { + var list = new List<(RightsId rightsId, AccessKey key)>(ExternalKeys.Count); + + foreach (KeyValuePair kvp in ExternalKeys) + { + list.Add((kvp.Key, kvp.Value)); + } + + return list; + } + } + + public void TrimExcess() => TrimExcess(0); + + public void TrimExcess(int capacity) + { + lock (_locker) + { + int newCapacity = Math.Max(capacity, ExternalKeys.Count); +#if NETCOREAPP + ExternalKeys.TrimExcess(newCapacity); +#else + var trimmedDict = new Dictionary(newCapacity); + + foreach (KeyValuePair kvp in ExternalKeys) + { + trimmedDict.Add(kvp.Key, kvp.Value); + } + + ExternalKeys = trimmedDict; +#endif + } + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index 0202cd03..f6c4a0d6 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -147,7 +147,7 @@ namespace LibHac.FsService private Result OpenSaveDataFileSystemImpl(out IFileSystem fileSystem, out ulong saveDataId, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData) { - bool hasFixedId = attribute.SaveDataId != 0 && attribute.UserId.Id == Id128.InvalidId; + bool hasFixedId = attribute.SaveDataId != 0 && attribute.UserId == UserId.Zero; if (hasFixedId) { diff --git a/src/LibHac/FsSystem/NcaUtils/Nca.cs b/src/LibHac/FsSystem/NcaUtils/Nca.cs index f10ae281..df7af1e8 100644 --- a/src/LibHac/FsSystem/NcaUtils/Nca.cs +++ b/src/LibHac/FsSystem/NcaUtils/Nca.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using LibHac.Fs; using LibHac.FsSystem.RomFs; +using LibHac.Spl; namespace LibHac.FsSystem.NcaUtils { @@ -47,9 +48,9 @@ namespace LibHac.FsSystem.NcaUtils int keyRevision = Util.GetMasterKeyRevision(Header.KeyGeneration); byte[] titleKek = Keyset.TitleKeks[keyRevision]; - if (!Keyset.TitleKeys.TryGetValue(Header.RightsId.ToArray(), out byte[] encryptedKey)) + if (Keyset.ExternalKeySet.Get(new RightsId(Header.RightsId), out AccessKey accessKey).IsFailure()) { - throw new MissingKeyException("Missing NCA title key.", Header.RightsId.ToHexString(), KeyType.Title); + throw new MissingKeyException("Missing NCA title key.", Header.RightsId.ToString(), KeyType.Title); } if (titleKek.IsEmpty()) @@ -58,6 +59,7 @@ namespace LibHac.FsSystem.NcaUtils throw new MissingKeyException("Unable to decrypt title key.", keyName, KeyType.Common); } + byte[] encryptedKey = accessKey.Value.ToArray(); var decryptedKey = new byte[Crypto.Aes128Size]; Crypto.DecryptEcb(titleKek, encryptedKey, decryptedKey, Crypto.Aes128Size); @@ -89,7 +91,7 @@ namespace LibHac.FsSystem.NcaUtils if (Header.HasRightsId) { - return Keyset.TitleKeys.ContainsKey(Header.RightsId.ToArray()) && + return Keyset.ExternalKeySet.Contains(new RightsId(Header.RightsId)) && !Keyset.TitleKeks[keyRevision].IsEmpty(); } diff --git a/src/LibHac/Keyset.cs b/src/LibHac/Keyset.cs index e71deaa8..7b51d616 100644 --- a/src/LibHac/Keyset.cs +++ b/src/LibHac/Keyset.cs @@ -4,7 +4,10 @@ using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; +using LibHac.Fs; +using LibHac.FsService; using LibHac.FsSystem; +using LibHac.Spl; namespace LibHac { @@ -129,7 +132,7 @@ namespace LibHac 0x49, 0x50, 0x95, 0x8C, 0x55, 0x80, 0x7E, 0x39, 0xB1, 0x48, 0x05, 0x1E, 0x21, 0xC7, 0x24, 0x4F }; - public Dictionary TitleKeys { get; } = new Dictionary(new ByteArray128BitComparer()); + public ExternalKeySet ExternalKeySet { get; } = new ExternalKeySet(); public void SetSdSeed(byte[] sdseed) { @@ -402,6 +405,7 @@ namespace LibHac if (filename != null) ReadMainKeys(keyset, filename, AllKeyDict, logger); if (consoleKeysFilename != null) ReadMainKeys(keyset, consoleKeysFilename, AllKeyDict, logger); if (titleKeysFilename != null) ReadTitleKeys(keyset, titleKeysFilename, logger); + keyset.ExternalKeySet.TrimExcess(); keyset.DeriveKeys(logger); } @@ -507,7 +511,7 @@ namespace LibHac continue; } - keyset.TitleKeys[rightsId] = titleKey; + keyset.ExternalKeySet.Add(new RightsId(rightsId), new AccessKey(titleKey)).ThrowIfFailure(); } } } @@ -557,9 +561,9 @@ namespace LibHac { var sb = new StringBuilder(); - foreach (KeyValuePair kv in keyset.TitleKeys.OrderBy(x => x.Key.ToHexString())) + foreach ((RightsId rightsId, AccessKey key) kv in keyset.ExternalKeySet.ToList().OrderBy(x => x.rightsId.ToString())) { - string line = $"{kv.Key.ToHexString()} = {kv.Value.ToHexString()}"; + string line = $"{kv.rightsId} = {kv.key}"; sb.AppendLine(line); } diff --git a/src/LibHac/LibHac.csproj b/src/LibHac/LibHac.csproj index c1033804..c0e7f166 100644 --- a/src/LibHac/LibHac.csproj +++ b/src/LibHac/LibHac.csproj @@ -3,7 +3,7 @@ Library netcoreapp2.1;netstandard2.0;net46 - 7.3 + 8.0 diff --git a/src/LibHac/Ncm/ContentId.cs b/src/LibHac/Ncm/ContentId.cs index 75c1d120..7df8ac93 100644 --- a/src/LibHac/Ncm/ContentId.cs +++ b/src/LibHac/Ncm/ContentId.cs @@ -1,9 +1,11 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; using LibHac.Common; namespace LibHac.Ncm { + [DebuggerDisplay("{ToString()}")] [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct ContentId : IEquatable, IComparable, IComparable { @@ -19,12 +21,13 @@ namespace LibHac.Ncm Id = new Id128(uid); } + public override string ToString() => Id.ToString(); + public bool Equals(ContentId other) => Id == other.Id; public override bool Equals(object obj) => obj is ContentId other && Equals(other); public override int GetHashCode() => Id.GetHashCode(); - // ReSharper disable once ImpureMethodCallOnReadonlyValueField public int CompareTo(ContentId other) => Id.CompareTo(other.Id); public int CompareTo(object obj) @@ -33,9 +36,13 @@ namespace LibHac.Ncm return obj is ContentId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(ContentId)}"); } - // ReSharper disable once ImpureMethodCallOnReadonlyValueField public void ToBytes(Span output) => Id.ToBytes(output); + public ReadOnlySpan AsBytes() + { + return SpanHelpers.AsByteSpan(ref this); + } + public static bool operator ==(ContentId left, ContentId right) => left.Equals(right); public static bool operator !=(ContentId left, ContentId right) => !left.Equals(right); diff --git a/src/LibHac/Ncm/PlaceHolderId.cs b/src/LibHac/Ncm/PlaceHolderId.cs index 0e31a14d..27ed1631 100644 --- a/src/LibHac/Ncm/PlaceHolderId.cs +++ b/src/LibHac/Ncm/PlaceHolderId.cs @@ -1,9 +1,11 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; using LibHac.Common; namespace LibHac.Ncm { + [DebuggerDisplay("{ToString()}")] [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct PlaceHolderId : IEquatable, IComparable, IComparable { @@ -19,12 +21,13 @@ namespace LibHac.Ncm Id = new Id128(uid); } + public override string ToString() => Id.ToString(); + public bool Equals(PlaceHolderId other) => Id == other.Id; public override bool Equals(object obj) => obj is PlaceHolderId other && Equals(other); public override int GetHashCode() => Id.GetHashCode(); - // ReSharper disable once ImpureMethodCallOnReadonlyValueField public int CompareTo(PlaceHolderId other) => Id.CompareTo(other.Id); public int CompareTo(object obj) @@ -33,9 +36,13 @@ namespace LibHac.Ncm return obj is PlaceHolderId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(PlaceHolderId)}"); } - // ReSharper disable once ImpureMethodCallOnReadonlyValueField public void ToBytes(Span output) => Id.ToBytes(output); + public ReadOnlySpan AsBytes() + { + return SpanHelpers.AsByteSpan(ref this); + } + public static bool operator ==(PlaceHolderId left, PlaceHolderId right) => left.Equals(right); public static bool operator !=(PlaceHolderId left, PlaceHolderId right) => !left.Equals(right); diff --git a/src/LibHac/Spl/AccessKey.cs b/src/LibHac/Spl/AccessKey.cs index 987a55b8..2a8e0be2 100644 --- a/src/LibHac/Spl/AccessKey.cs +++ b/src/LibHac/Spl/AccessKey.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using LibHac.Common; @@ -8,13 +7,23 @@ namespace LibHac.Spl { [DebuggerDisplay("{ToString()}")] [StructLayout(LayoutKind.Sequential, Size = 0x10)] - public struct AccessKey + public struct AccessKey : IEquatable { - private long _dummy1; - private long _dummy2; + private readonly Key128 Key; - public Span Key => SpanHelpers.CreateSpan(ref Unsafe.As(ref _dummy1), 0x10); + public ReadOnlySpan Value => SpanHelpers.AsByteSpan(ref this); - public override string ToString() => Key.ToHexString(); + public AccessKey(ReadOnlySpan bytes) + { + Key = new Key128(bytes); + } + + public override string ToString() => Key.ToString(); + + public override bool Equals(object obj) => obj is AccessKey key && Equals(key); + public bool Equals(AccessKey other) => Key.Equals(other.Key); + public override int GetHashCode() => Key.GetHashCode(); + public static bool operator ==(AccessKey left, AccessKey right) => left.Equals(right); + public static bool operator !=(AccessKey left, AccessKey right) => !(left == right); } } diff --git a/src/LibHac/Util.cs b/src/LibHac/Util.cs index d9f1a5e0..ea20c212 100644 --- a/src/LibHac/Util.cs +++ b/src/LibHac/Util.cs @@ -354,7 +354,9 @@ namespace LibHac public static string ToHexString(this byte[] bytes) => ToHexString(bytes.AsSpan()); - public static string ToHexString(this Span bytes) + public static string ToHexString(this Span bytes) => ToHexString((ReadOnlySpan)bytes); + + public static string ToHexString(this ReadOnlySpan bytes) { uint[] lookup32 = Lookup32; var result = new char[bytes.Length * 2]; From fdd7eebb4bb4a00922ebc27db8135179cf7eb781 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Wed, 2 Oct 2019 17:57:10 -0500 Subject: [PATCH 35/46] Add external key methods to FS client/server --- src/LibHac/Fs/ExternalKeys.cs | 38 +++++++++++++++++++++ src/LibHac/FsService/FileSystemProxy.cs | 13 +++++-- src/LibHac/FsService/FileSystemProxyCore.cs | 24 ++++++++++++- src/LibHac/FsService/FileSystemServer.cs | 7 ++-- src/LibHac/Keyset.cs | 4 +-- src/hactoolnet/Program.cs | 10 +++--- 6 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 src/LibHac/Fs/ExternalKeys.cs diff --git a/src/LibHac/Fs/ExternalKeys.cs b/src/LibHac/Fs/ExternalKeys.cs new file mode 100644 index 00000000..8ee8b883 --- /dev/null +++ b/src/LibHac/Fs/ExternalKeys.cs @@ -0,0 +1,38 @@ +using LibHac.FsService; +using LibHac.Ncm; +using LibHac.Spl; + +namespace LibHac.Fs +{ + public static class ExternalKeys + { + public static Result GetRightsId(this FileSystemClient fs, out RightsId rightsId, TitleId programId, + StorageId storageId) + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + return fsProxy.GetRightsId(out rightsId, programId, storageId); + } + + public static Result RegisterExternalKey(this FileSystemClient fs, ref RightsId rightsId, ref AccessKey key) + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + return fsProxy.RegisterExternalKey(ref rightsId, ref key); + } + + public static Result UnregisterExternalKey(this FileSystemClient fs, ref RightsId rightsId) + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + return fsProxy.UnregisterExternalKey(ref rightsId); + } + + public static Result UnregisterAllExternalKey(this FileSystemClient fs) + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + return fsProxy.UnregisterAllExternalKey(); + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index f6c4a0d6..adc67c3c 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -451,18 +451,25 @@ namespace LibHac.FsService public Result RegisterExternalKey(ref RightsId rightsId, ref AccessKey externalKey) { - throw new NotImplementedException(); + // Missing permission check + + return FsProxyCore.RegisterExternalKey(ref rightsId, ref externalKey); } public Result UnregisterExternalKey(ref RightsId rightsId) { - throw new NotImplementedException(); + // Missing permission check + + return FsProxyCore.UnregisterExternalKey(ref rightsId); } public Result UnregisterAllExternalKey() { - throw new NotImplementedException(); + // Missing permission check + + return FsProxyCore.UnregisterAllExternalKey(); } + public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) { // todo: use struct instead of byte span diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index b3df317f..8bda0eaf 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -3,12 +3,14 @@ using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.Save; using LibHac.FsService.Creators; +using LibHac.Spl; namespace LibHac.FsService { public class FileSystemProxyCore { private FileSystemCreators FsCreators { get; } + private ExternalKeySet ExternalKeys { get; } private byte[] SdEncryptionSeed { get; } = new byte[0x10]; private const string NintendoDirectoryName = "Nintendo"; @@ -16,9 +18,10 @@ namespace LibHac.FsService private GlobalAccessLogMode LogMode { get; set; } - public FileSystemProxyCore(FileSystemCreators fsCreators) + public FileSystemProxyCore(FileSystemCreators fsCreators, ExternalKeySet externalKeys) { FsCreators = fsCreators; + ExternalKeys = externalKeys ?? new ExternalKeySet(); } public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) @@ -122,6 +125,25 @@ namespace LibHac.FsService } } + public Result RegisterExternalKey(ref RightsId rightsId, ref AccessKey externalKey) + { + return ExternalKeys.Add(rightsId, externalKey); + } + + public Result UnregisterExternalKey(ref RightsId rightsId) + { + ExternalKeys.Remove(rightsId); + + return Result.Success; + } + + public Result UnregisterAllExternalKey() + { + ExternalKeys.Clear(); + + return Result.Success; + } + public Result SetSdCardEncryptionSeed(ReadOnlySpan seed) { seed.CopyTo(SdEncryptionSeed); diff --git a/src/LibHac/FsService/FileSystemServer.cs b/src/LibHac/FsService/FileSystemServer.cs index 09d17f40..7e6338c0 100644 --- a/src/LibHac/FsService/FileSystemServer.cs +++ b/src/LibHac/FsService/FileSystemServer.cs @@ -15,16 +15,17 @@ namespace LibHac.FsService /// Creates a new with a new default . /// /// The used for creating filesystems. - public FileSystemServer(FileSystemCreators fsCreators) : this(fsCreators, new StopWatchTimeSpanGenerator()) { } + public FileSystemServer(FileSystemCreators fsCreators) : this(fsCreators, null, new StopWatchTimeSpanGenerator()) { } /// /// Creates a new . /// /// The used for creating filesystems. + /// A keyset containing rights IDs and title keys. If null, an empty set will be created. /// The to use for access log timestamps. - public FileSystemServer(FileSystemCreators fsCreators, ITimeSpanGenerator timer) + public FileSystemServer(FileSystemCreators fsCreators, ExternalKeySet externalKeys, ITimeSpanGenerator timer) { - FsProxyCore = new FileSystemProxyCore(fsCreators); + FsProxyCore = new FileSystemProxyCore(fsCreators, externalKeys); FsClient = new FileSystemClient(this, timer); Timer = timer; } diff --git a/src/LibHac/Keyset.cs b/src/LibHac/Keyset.cs index 7b51d616..15513df2 100644 --- a/src/LibHac/Keyset.cs +++ b/src/LibHac/Keyset.cs @@ -382,7 +382,7 @@ namespace LibHac } } - public static class ExternalKeys + public static class ExternalKeyReader { private const int TitleKeySize = 0x10; @@ -390,7 +390,7 @@ namespace LibHac public static readonly Dictionary UniqueKeyDict; public static readonly Dictionary AllKeyDict; - static ExternalKeys() + static ExternalKeyReader() { List commonKeys = CreateCommonKeyList(); List uniqueKeys = CreateUniqueKeyList(); diff --git a/src/hactoolnet/Program.cs b/src/hactoolnet/Program.cs index 84ed4fb8..c352c039 100644 --- a/src/hactoolnet/Program.cs +++ b/src/hactoolnet/Program.cs @@ -174,7 +174,7 @@ namespace hactoolnet consoleKeyFile = homeConsoleKeyFile; } - ctx.Keyset = ExternalKeys.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile, ctx.Logger); + ctx.Keyset = ExternalKeyReader.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile, ctx.Logger); if (ctx.Options.SdSeed != null) { ctx.Keyset.SetSdSeed(ctx.Options.SdSeed.ToBytes()); @@ -185,15 +185,15 @@ namespace hactoolnet string dir = ctx.Options.OutDir; Directory.CreateDirectory(dir); - File.WriteAllText(Path.Combine(dir, keyFileName), ExternalKeys.PrintCommonKeys(ctx.Keyset)); - File.WriteAllText(Path.Combine(dir, "console.keys"), ExternalKeys.PrintUniqueKeys(ctx.Keyset)); - File.WriteAllText(Path.Combine(dir, "title.keys"), ExternalKeys.PrintTitleKeys(ctx.Keyset)); + File.WriteAllText(Path.Combine(dir, keyFileName), ExternalKeyReader.PrintCommonKeys(ctx.Keyset)); + File.WriteAllText(Path.Combine(dir, "console.keys"), ExternalKeyReader.PrintUniqueKeys(ctx.Keyset)); + File.WriteAllText(Path.Combine(dir, "title.keys"), ExternalKeyReader.PrintTitleKeys(ctx.Keyset)); } } private static void ProcessKeygen(Context ctx) { - Console.WriteLine(ExternalKeys.PrintCommonKeys(ctx.Keyset)); + Console.WriteLine(ExternalKeyReader.PrintCommonKeys(ctx.Keyset)); } // For running random stuff From 9934f477d5f06d9e4efbf739a47cd1676e838297 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Thu, 3 Oct 2019 23:23:30 -0500 Subject: [PATCH 36/46] Add remaining GetRightsId methods and U8StringBuilder --- src/LibHac/Common/PaddingStructs.cs | 38 ++++++++++++ src/LibHac/Common/U8StringBuilder.cs | 86 ++++++++++++++++++++++++++++ src/LibHac/Fs/ExternalKeys.cs | 29 +++++++++- src/LibHac/FsSystem/FsPath.cs | 21 ++++++- src/LibHac/Ncm/TitleId.cs | 12 +++- 5 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 src/LibHac/Common/PaddingStructs.cs create mode 100644 src/LibHac/Common/U8StringBuilder.cs diff --git a/src/LibHac/Common/PaddingStructs.cs b/src/LibHac/Common/PaddingStructs.cs new file mode 100644 index 00000000..92ac14d7 --- /dev/null +++ b/src/LibHac/Common/PaddingStructs.cs @@ -0,0 +1,38 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace LibHac.Common +{ + // In order for the Visual Studio debugger to accurately display a struct, every offset + // in the struct that is used for the debugger display must be part of a field. + // These padding structs make it easier to accomplish that. + [StructLayout(LayoutKind.Sequential, Size = 0x20)] + internal struct Padding20 + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding00; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding08; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding10; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding18; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x40)] + internal struct Padding40 + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding20 Padding00; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding20 Padding20; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x80)] + internal struct Padding80 + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding40 Padding00; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding40 Padding40; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x100)] + internal struct Padding100 + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding80 Padding00; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding80 Padding80; + } +} diff --git a/src/LibHac/Common/U8StringBuilder.cs b/src/LibHac/Common/U8StringBuilder.cs new file mode 100644 index 00000000..cbaed2f1 --- /dev/null +++ b/src/LibHac/Common/U8StringBuilder.cs @@ -0,0 +1,86 @@ +using System; +using System.Diagnostics; + +namespace LibHac.Common +{ + [DebuggerDisplay("{ToString()}")] + public ref struct U8StringBuilder + { + private const int NullTerminatorLength = 1; + + private readonly Span _buffer; + private int _length; + + public bool Overflowed { get; private set; } + public int Capacity => _buffer.Length - NullTerminatorLength; + + public U8StringBuilder(Span buffer) + { + _buffer = buffer; + _length = 0; + Overflowed = false; + + ThrowIfBufferLengthIsZero(); + + AddNullTerminator(); + } + + public U8StringBuilder Append(ReadOnlySpan value) + { + if (Overflowed) return this; + + int valueLength = StringUtils.GetLength(value); + + if (!HasAdditionalCapacity(valueLength)) + { + Overflowed = true; + return this; + } + + value.Slice(0, valueLength).CopyTo(_buffer.Slice(_length)); + _length += valueLength; + AddNullTerminator(); + + return this; + } + + public U8StringBuilder Append(byte value) + { + if (Overflowed) return this; + + if (!HasAdditionalCapacity(1)) + { + Overflowed = true; + return this; + } + + _buffer[_length] = value; + _length++; + AddNullTerminator(); + + return this; + } + + private bool HasCapacity(int requiredCapacity) + { + return requiredCapacity <= Capacity; + } + + private bool HasAdditionalCapacity(int requiredAdditionalCapacity) + { + return HasCapacity(_length + requiredAdditionalCapacity); + } + + private void AddNullTerminator() + { + _buffer[_length] = 0; + } + + private void ThrowIfBufferLengthIsZero() + { + if (_buffer.Length == 0) throw new ArgumentException("Buffer length must be greater than 0."); + } + + public override string ToString() => StringUtils.Utf8ZToString(_buffer); + } +} diff --git a/src/LibHac/Fs/ExternalKeys.cs b/src/LibHac/Fs/ExternalKeys.cs index 8ee8b883..e0638600 100644 --- a/src/LibHac/Fs/ExternalKeys.cs +++ b/src/LibHac/Fs/ExternalKeys.cs @@ -1,4 +1,6 @@ -using LibHac.FsService; +using LibHac.Common; +using LibHac.FsService; +using LibHac.FsSystem; using LibHac.Ncm; using LibHac.Spl; @@ -14,6 +16,31 @@ namespace LibHac.Fs return fsProxy.GetRightsId(out rightsId, programId, storageId); } + public static Result GetRightsId(this FileSystemClient fs, out RightsId rightsId, U8Span path) + { + rightsId = default; + + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + Result rc = FsPath.FromSpan(out FsPath fsPath, path); + if (rc.IsFailure()) return rc; + + return fsProxy.GetRightsIdByPath(out rightsId, ref fsPath); + } + + public static Result GetRightsId(this FileSystemClient fs, out RightsId rightsId, out byte keyGeneration, U8Span path) + { + rightsId = default; + keyGeneration = default; + + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + Result rc = FsPath.FromSpan(out FsPath fsPath, path); + if (rc.IsFailure()) return rc; + + return fsProxy.GetRightsIdAndKeyGenerationByPath(out rightsId, out keyGeneration, ref fsPath); + } + public static Result RegisterExternalKey(this FileSystemClient fs, ref RightsId rightsId, ref AccessKey key) { IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); diff --git a/src/LibHac/FsSystem/FsPath.cs b/src/LibHac/FsSystem/FsPath.cs index af82bb49..6da1475e 100644 --- a/src/LibHac/FsSystem/FsPath.cs +++ b/src/LibHac/FsSystem/FsPath.cs @@ -2,18 +2,33 @@ using System.Diagnostics; using System.Runtime.InteropServices; using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem { [DebuggerDisplay("{ToString()}")] - [StructLayout(LayoutKind.Explicit, Size = MaxLength + 1)] + [StructLayout(LayoutKind.Sequential, Size = MaxLength + 1)] public struct FsPath { internal const int MaxLength = 0x300; - [FieldOffset(0)] private byte _str; +#if DEBUG + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding000; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding100; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding200; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte Padding300; +#endif - public Span Str => SpanHelpers.CreateSpan(ref _str, MaxLength + 1); + public Span Str => SpanHelpers.AsByteSpan(ref this); + + public static Result FromSpan(out FsPath fsPath, ReadOnlySpan path) + { + fsPath = new FsPath(); + + U8StringBuilder builder = new U8StringBuilder(fsPath.Str).Append(path); + + return builder.Overflowed ? ResultFs.TooLongPath : Result.Success; + } public static implicit operator U8Span(FsPath value) => new U8Span(value.Str); public override string ToString() => StringUtils.Utf8ZToString(Str); diff --git a/src/LibHac/Ncm/TitleId.cs b/src/LibHac/Ncm/TitleId.cs index 9502bf10..0288bd7b 100644 --- a/src/LibHac/Ncm/TitleId.cs +++ b/src/LibHac/Ncm/TitleId.cs @@ -1,8 +1,16 @@ -namespace LibHac.Ncm +using System.Diagnostics; + +namespace LibHac.Ncm { + [DebuggerDisplay("{" + nameof(Value) + "}")] public struct TitleId { - public ulong Value; + public readonly ulong Value; + + public TitleId(ulong value) + { + Value = value; + } public static explicit operator ulong(TitleId titleId) => titleId.Value; } From 51a13068df0234cd8b0c3fc79d8d8a78c423c324 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 7 Oct 2019 18:39:06 -0500 Subject: [PATCH 37/46] Add an emulated gamecard and storage creator --- src/LibHac/Fs/GameCard.cs | 79 +++++++++++ src/LibHac/Fs/ResultFs.cs | 11 ++ .../EmulatedGameCardStorageCreator.cs | 125 ++++++++++++++++++ .../FsService/Creators/FileSystemCreators.cs | 11 +- .../FsService/EmulatedDeviceOperator.cs | 38 ++++++ src/LibHac/FsService/EmulatedGameCard.cs | 103 +++++++++++++++ src/LibHac/FsService/FileSystemProxy.cs | 8 +- src/LibHac/FsService/FileSystemProxyCore.cs | 26 +++- src/LibHac/FsService/FileSystemServer.cs | 56 ++++++-- src/LibHac/FsService/GameCardHandle.cs | 19 ++- src/LibHac/FsService/GameCardInfo.cs | 18 +++ src/LibHac/Horizon.cs | 9 +- src/LibHac/XciHeader.cs | 34 ++--- src/hactoolnet/ProcessXci.cs | 16 +-- 14 files changed, 498 insertions(+), 55 deletions(-) create mode 100644 src/LibHac/Fs/GameCard.cs create mode 100644 src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs create mode 100644 src/LibHac/FsService/EmulatedDeviceOperator.cs create mode 100644 src/LibHac/FsService/EmulatedGameCard.cs create mode 100644 src/LibHac/FsService/GameCardInfo.cs diff --git a/src/LibHac/Fs/GameCard.cs b/src/LibHac/Fs/GameCard.cs new file mode 100644 index 00000000..70680e4a --- /dev/null +++ b/src/LibHac/Fs/GameCard.cs @@ -0,0 +1,79 @@ +using System; +using LibHac.FsService; + +namespace LibHac.Fs +{ + public static class GameCard + { + public static Result OpenGameCardPartition(this FileSystemClient fs, out IStorage storage, + GameCardHandle handle, GameCardPartitionRaw partitionType) + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + return fsProxy.OpenGameCardStorage(out storage, handle, partitionType); + } + + public static Result GetGameCardHandle(this FileSystemClient fs, out GameCardHandle handle) + { + handle = default; + + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + Result rc = fsProxy.OpenDeviceOperator(out IDeviceOperator deviceOperator); + if (rc.IsFailure()) return rc; + + return deviceOperator.GetGameCardHandle(out handle); + } + + public static bool IsGameCardInserted(this FileSystemClient fs) + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + Result rc = fsProxy.OpenDeviceOperator(out IDeviceOperator deviceOperator); + if (rc.IsFailure()) throw new LibHacException("Abort"); + + rc = deviceOperator.IsGameCardInserted(out bool isInserted); + if (rc.IsFailure()) throw new LibHacException("Abort"); + + return isInserted; + } + + public static long GetGameCardSizeBytes(GameCardSize size) + { + switch (size) + { + case GameCardSize.Size1Gb: return 0x3B800000; + case GameCardSize.Size2Gb: return 0x77000000; + case GameCardSize.Size4Gb: return 0xEE000000; + case GameCardSize.Size8Gb: return 0x1DC000000; + case GameCardSize.Size16Gb: return 0x3B8000000; + case GameCardSize.Size32Gb: return 0x770000000; + default: + throw new ArgumentOutOfRangeException(nameof(size), size, null); + } + } + + public static long CardPageToOffset(int page) + { + return (long)page << 9; + } + } + + public enum GameCardSize + { + Size1Gb = 0xFA, + Size2Gb = 0xF8, + Size4Gb = 0xF0, + Size8Gb = 0xE0, + Size16Gb = 0xE1, + Size32Gb = 0xE2 + } + + [Flags] + public enum GameCardAttribute : byte + { + AutoBoot = 1 << 0, + HistoryErase = 1 << 1, + RepairTool = 1 << 2 + } +} diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index b9d4edfe..1922b40e 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -15,6 +15,15 @@ public static Result TargetNotFound => new Result(ModuleFs, 1002); public static Result ExternalKeyNotFound => new Result(ModuleFs, 1004); + public static Result InvalidBufferForGameCard => new Result(ModuleFs, 2503); + public static Result GameCardNotInserted => new Result(ModuleFs, 2520); + + public static Result GameCardNotInsertedOnGetHandle => new Result(ModuleFs, 2951); + public static Result InvalidGameCardHandleOnRead => new Result(ModuleFs, 2952); + public static Result InvalidGameCardHandleOnGetCardInfo => new Result(ModuleFs, 2954); + public static Result InvalidGameCardHandleOnOpenNormalPartition => new Result(ModuleFs, 2960); + public static Result InvalidGameCardHandleOnOpenSecurePartition => new Result(ModuleFs, 2961); + public static Result NotImplemented => new Result(ModuleFs, 3001); public static Result Result3002 => new Result(ModuleFs, 3002); public static Result SaveDataPathAlreadyExists => new Result(ModuleFs, 3003); @@ -98,6 +107,8 @@ public static Result UnsupportedOperationInAesCtrExStorageWrite => new Result(ModuleFs, 6310); public static Result UnsupportedOperationInIndirectStorageWrite => new Result(ModuleFs, 6324); public static Result UnsupportedOperationInIndirectStorageSetSize => new Result(ModuleFs, 6325); + public static Result UnsupportedOperationInRoGameCardStorageWrite => new Result(ModuleFs, 6350); + public static Result UnsupportedOperationInRoGameCardStorageSetSize => new Result(ModuleFs, 6351); public static Result UnsupportedOperationInConcatFsQueryEntry => new Result(ModuleFs, 6359); public static Result UnsupportedOperationModifyRomFsFileSystem => new Result(ModuleFs, 6364); public static Result UnsupportedOperationRomFsFileSystemGetSpace => new Result(ModuleFs, 6366); diff --git a/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs new file mode 100644 index 00000000..a0b73f52 --- /dev/null +++ b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs @@ -0,0 +1,125 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService.Creators +{ + class EmulatedGameCardStorageCreator : IGameCardStorageCreator + { + private EmulatedGameCard GameCard { get; } + + public EmulatedGameCardStorageCreator(EmulatedGameCard gameCard) + { + GameCard = gameCard; + } + + public Result CreateNormal(GameCardHandle handle, out IStorage storage) + { + storage = default; + + if (GameCard.IsGameCardHandleInvalid(handle)) + { + return ResultFs.InvalidGameCardHandleOnOpenNormalPartition.Log(); + } + + var baseStorage = new ReadOnlyGameCardStorage(GameCard, handle); + + Result rc = GameCard.GetCardInfo(out GameCardInfo cardInfo, handle); + if (rc.IsFailure()) return rc; + + storage = new SubStorage2(baseStorage, 0, cardInfo.SecureAreaOffset); + return Result.Success; + } + + public Result CreateSecure(GameCardHandle handle, out IStorage storage) + { + storage = default; + + if (GameCard.IsGameCardHandleInvalid(handle)) + { + return ResultFs.InvalidGameCardHandleOnOpenSecurePartition.Log(); + } + + Span deviceId = stackalloc byte[0x10]; + Span imageHash = stackalloc byte[0x20]; + + Result rc = GameCard.GetGameCardDeviceId(deviceId); + if (rc.IsFailure()) return rc; + + rc = GameCard.GetGameCardImageHash(imageHash); + if (rc.IsFailure()) return rc; + + var baseStorage = new ReadOnlyGameCardStorage(GameCard, handle, deviceId, imageHash); + + rc = GameCard.GetCardInfo(out GameCardInfo cardInfo, handle); + if (rc.IsFailure()) return rc; + + storage = new SubStorage2(baseStorage, cardInfo.SecureAreaOffset, cardInfo.SecureAreaSize); + return Result.Success; + } + + public Result CreateWritable(GameCardHandle handle, out IStorage storage) + { + throw new NotImplementedException(); + } + + private class ReadOnlyGameCardStorage : StorageBase + { + private EmulatedGameCard GameCard { get; } + private GameCardHandle Handle { get; set; } + + // ReSharper disable once UnusedAutoPropertyAccessor.Local + private bool IsSecureMode { get; } + private byte[] DeviceId { get; } = new byte[0x10]; + private byte[] ImageHash { get; } = new byte[0x20]; + + public ReadOnlyGameCardStorage(EmulatedGameCard gameCard, GameCardHandle handle) + { + GameCard = gameCard; + Handle = handle; + } + + public ReadOnlyGameCardStorage(EmulatedGameCard gameCard, GameCardHandle handle, ReadOnlySpan deviceId, ReadOnlySpan imageHash) + { + GameCard = gameCard; + Handle = handle; + IsSecureMode = true; + deviceId.CopyTo(DeviceId); + imageHash.CopyTo(ImageHash); + } + + public override Result Read(long offset, Span destination) + { + // In secure mode, if Handle is old and the card's device ID and + // header hash are still the same, Handle is updated to the new handle + + return GameCard.Read(Handle, offset, destination); + } + + public override Result Write(long offset, ReadOnlySpan source) + { + return ResultFs.UnsupportedOperationInRoGameCardStorageWrite.Log(); + } + + public override Result Flush() + { + return Result.Success; + } + + public override Result SetSize(long size) + { + return ResultFs.UnsupportedOperationInRoGameCardStorageSetSize.Log(); + } + + public override Result GetSize(out long size) + { + size = 0; + + Result rc = GameCard.GetCardInfo(out GameCardInfo info, Handle); + if (rc.IsFailure()) return rc; + + size = info.Size; + return Result.Success; + } + } + } +} diff --git a/src/LibHac/FsService/Creators/FileSystemCreators.cs b/src/LibHac/FsService/Creators/FileSystemCreators.cs index c0f83871..08b35243 100644 --- a/src/LibHac/FsService/Creators/FileSystemCreators.cs +++ b/src/LibHac/FsService/Creators/FileSystemCreators.cs @@ -21,17 +21,24 @@ namespace LibHac.FsService.Creators public IBuiltInStorageFileSystemCreator BuiltInStorageFileSystemCreator { get; set; } public ISdFileSystemCreator SdFileSystemCreator { get; set; } - public static FileSystemCreators GetDefaultEmulatedCreators(IFileSystem rootFileSystem, Keyset keyset) + public IDeviceOperator DeviceOperator { get; set; } + + public static (FileSystemCreators fsCreators, EmulatedGameCard gameCard) GetDefaultEmulatedCreators( + IFileSystem rootFileSystem, Keyset keyset) { var creators = new FileSystemCreators(); + var gameCard = new EmulatedGameCard(); creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(keyset); + creators.GameCardStorageCreator = new EmulatedGameCardStorageCreator(gameCard); creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keyset); creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem); creators.SdFileSystemCreator = new EmulatedSdFileSystemCreator(rootFileSystem); - return creators; + creators.DeviceOperator = new EmulatedDeviceOperator(gameCard); + + return (creators, gameCard); } } } diff --git a/src/LibHac/FsService/EmulatedDeviceOperator.cs b/src/LibHac/FsService/EmulatedDeviceOperator.cs new file mode 100644 index 00000000..5e529756 --- /dev/null +++ b/src/LibHac/FsService/EmulatedDeviceOperator.cs @@ -0,0 +1,38 @@ +using System; +using LibHac.Fs; + +namespace LibHac.FsService +{ + class EmulatedDeviceOperator : IDeviceOperator + { + private EmulatedGameCard GameCard { get; set; } + + public EmulatedDeviceOperator(EmulatedGameCard gameCard) + { + GameCard = gameCard; + } + + public Result IsSdCardInserted(out bool isInserted) + { + throw new NotImplementedException(); + } + + public Result IsGameCardInserted(out bool isInserted) + { + isInserted = GameCard.IsGameCardInserted(); + return Result.Success; + } + + public Result GetGameCardHandle(out GameCardHandle handle) + { + if (!GameCard.IsGameCardInserted()) + { + handle = default; + return ResultFs.GameCardNotInsertedOnGetHandle.Log(); + } + + handle = GameCard.GetGameCardHandle(); + return Result.Success; + } + } +} diff --git a/src/LibHac/FsService/EmulatedGameCard.cs b/src/LibHac/FsService/EmulatedGameCard.cs new file mode 100644 index 00000000..e3e8ec25 --- /dev/null +++ b/src/LibHac/FsService/EmulatedGameCard.cs @@ -0,0 +1,103 @@ +using System; +using LibHac.Fs; +using LibHac.FsSystem; + +namespace LibHac.FsService +{ + public class EmulatedGameCard + { + private IStorage CardImageStorage { get; set; } + private int Handle { get; set; } + private XciHeader CardHeader { get; set; } + + public GameCardHandle GetGameCardHandle() + { + return new GameCardHandle(Handle); + } + + public bool IsGameCardHandleInvalid(GameCardHandle handle) + { + return Handle != handle.Value; + } + + public bool IsGameCardInserted() + { + return CardImageStorage != null; + } + + public void InsertGameCard(IStorage cardImageStorage) + { + RemoveGameCard(); + + CardImageStorage = cardImageStorage; + + CardHeader = new XciHeader(null, cardImageStorage.AsStream()); + } + + public void RemoveGameCard() + { + if (IsGameCardInserted()) + { + CardImageStorage = null; + Handle++; + } + } + + public Result Read(GameCardHandle handle, long offset, Span destination) + { + if (IsGameCardHandleInvalid(handle)) return ResultFs.InvalidGameCardHandleOnRead.Log(); + if (!IsGameCardInserted()) return ResultFs.GameCardNotInserted.Log(); + + return CardImageStorage.Read(offset, destination); + } + + public Result GetGameCardImageHash(Span outBuffer) + { + if (outBuffer.Length < 0x20) return ResultFs.InvalidBufferForGameCard.Log(); + if (!IsGameCardInserted()) return ResultFs.GameCardNotInserted.Log(); + + CardHeader.ImageHash.CopyTo(outBuffer.Slice(0, 0x20)); + return Result.Success; + } + + public Result GetGameCardDeviceId(Span outBuffer) + { + if (outBuffer.Length < 0x10) return ResultFs.InvalidBufferForGameCard.Log(); + if (!IsGameCardInserted()) return ResultFs.GameCardNotInserted.Log(); + + // Skip the security mode check + + // Instead of caching the CardKeyArea data, read the value directly + return CardImageStorage.Read(0x7110, outBuffer.Slice(0, 0x10)); + } + + internal Result GetCardInfo(out GameCardInfo cardInfo, GameCardHandle handle) + { + cardInfo = default; + + if (IsGameCardHandleInvalid(handle)) return ResultFs.InvalidGameCardHandleOnGetCardInfo.Log(); + if (!IsGameCardInserted()) return ResultFs.GameCardNotInserted.Log(); + + cardInfo = GetCardInfoImpl(); + return Result.Success; + } + + private GameCardInfo GetCardInfoImpl() + { + var info = new GameCardInfo(); + + CardHeader.RootPartitionHeaderHash.AsSpan().CopyTo(info.RootPartitionHeaderHash); + info.PackageId = CardHeader.PackageId; + info.Size = GameCard.GetGameCardSizeBytes(CardHeader.GameCardSize); + info.RootPartitionOffset = CardHeader.RootPartitionOffset; + info.RootPartitionHeaderSize = CardHeader.RootPartitionHeaderSize; + info.SecureAreaOffset = GameCard.CardPageToOffset(CardHeader.LimAreaPage); + info.SecureAreaSize = info.Size - info.SecureAreaOffset; + info.UpdateVersion = CardHeader.UppVersion; + info.UpdateTitleId = CardHeader.UppId; + info.Attribute = CardHeader.Flags; + + return info; + } + } +} diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index adc67c3c..b16566ec 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -302,12 +302,16 @@ namespace LibHac.FsService public Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId) { - throw new NotImplementedException(); + // Missing permission check and StorageInterfaceAdapter + + return FsProxyCore.OpenGameCardStorage(out storage, handle, partitionId); } public Result OpenDeviceOperator(out IDeviceOperator deviceOperator) { - throw new NotImplementedException(); + // Missing permission check + + return FsProxyCore.OpenDeviceOperator(out deviceOperator); } public Result OpenSaveDataInfoReader(out ISaveDataInfoReader infoReader) diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 8bda0eaf..df691c0b 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -11,6 +11,8 @@ namespace LibHac.FsService { private FileSystemCreators FsCreators { get; } private ExternalKeySet ExternalKeys { get; } + private IDeviceOperator DeviceOperator { get; } + private byte[] SdEncryptionSeed { get; } = new byte[0x10]; private const string NintendoDirectoryName = "Nintendo"; @@ -18,10 +20,11 @@ namespace LibHac.FsService private GlobalAccessLogMode LogMode { get; set; } - public FileSystemProxyCore(FileSystemCreators fsCreators, ExternalKeySet externalKeys) + public FileSystemProxyCore(FileSystemCreators fsCreators, ExternalKeySet externalKeys, IDeviceOperator deviceOperator) { FsCreators = fsCreators; ExternalKeys = externalKeys ?? new ExternalKeySet(); + DeviceOperator = deviceOperator; } public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) @@ -34,6 +37,27 @@ namespace LibHac.FsService return FsCreators.SdFileSystemCreator.Create(out fileSystem); } + public Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId) + { + switch (partitionId) + { + case GameCardPartitionRaw.Normal: + return FsCreators.GameCardStorageCreator.CreateNormal(handle, out storage); + case GameCardPartitionRaw.Secure: + return FsCreators.GameCardStorageCreator.CreateSecure(handle, out storage); + case GameCardPartitionRaw.Writable: + return FsCreators.GameCardStorageCreator.CreateWritable(handle, out storage); + default: + throw new ArgumentOutOfRangeException(nameof(partitionId), partitionId, null); + } + } + + public Result OpenDeviceOperator(out IDeviceOperator deviceOperator) + { + deviceOperator = DeviceOperator; + return Result.Success; + } + public Result OpenContentStorageFileSystem(out IFileSystem fileSystem, ContentStorageId storageId) { fileSystem = default; diff --git a/src/LibHac/FsService/FileSystemServer.cs b/src/LibHac/FsService/FileSystemServer.cs index 7e6338c0..c1ae6de2 100644 --- a/src/LibHac/FsService/FileSystemServer.cs +++ b/src/LibHac/FsService/FileSystemServer.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using System; +using LibHac.Fs; using LibHac.FsService.Creators; namespace LibHac.FsService @@ -10,22 +11,23 @@ namespace LibHac.FsService /// The client instance to be used for internal operations like save indexer access. private FileSystemClient FsClient { get; } private ITimeSpanGenerator Timer { get; } - - /// - /// Creates a new with a new default . - /// - /// The used for creating filesystems. - public FileSystemServer(FileSystemCreators fsCreators) : this(fsCreators, null, new StopWatchTimeSpanGenerator()) { } - + /// /// Creates a new . /// - /// The used for creating filesystems. - /// A keyset containing rights IDs and title keys. If null, an empty set will be created. - /// The to use for access log timestamps. - public FileSystemServer(FileSystemCreators fsCreators, ExternalKeySet externalKeys, ITimeSpanGenerator timer) + /// The configuration for the created . + public FileSystemServer(FileSystemServerConfig config) { - FsProxyCore = new FileSystemProxyCore(fsCreators, externalKeys); + if(config.FsCreators == null) + throw new ArgumentException("FsCreators must not be null"); + + if(config.DeviceOperator == null) + throw new ArgumentException("DeviceOperator must not be null"); + + ExternalKeySet externalKeySet = config.ExternalKeySet ?? new ExternalKeySet(); + ITimeSpanGenerator timer = config.TimeSpanGenerator ?? new StopWatchTimeSpanGenerator(); + + FsProxyCore = new FileSystemProxyCore(config.FsCreators, externalKeySet, config.DeviceOperator); FsClient = new FileSystemClient(this, timer); Timer = timer; } @@ -53,4 +55,32 @@ namespace LibHac.FsService return new FileSystemProxy(FsProxyCore, FsClient); } } + + /// + /// Contains the configuration for creating a new . + /// + public class FileSystemServerConfig + { + /// + /// The used for creating filesystems. + /// + public FileSystemCreators FsCreators { get; set; } + + /// + /// An for managing the gamecard and SD card. + /// + public IDeviceOperator DeviceOperator { get; set; } + + /// + /// A keyset containing rights IDs and title keys. + /// If null, an empty set will be created. + /// + public ExternalKeySet ExternalKeySet { get; set; } + + /// + /// Used for generating access log timestamps. + /// If null, a new will be created. + /// + public ITimeSpanGenerator TimeSpanGenerator { get; set; } + } } diff --git a/src/LibHac/FsService/GameCardHandle.cs b/src/LibHac/FsService/GameCardHandle.cs index 1753a869..21214ad8 100644 --- a/src/LibHac/FsService/GameCardHandle.cs +++ b/src/LibHac/FsService/GameCardHandle.cs @@ -1,7 +1,20 @@ -namespace LibHac.FsService +using System; + +namespace LibHac.FsService { - public struct GameCardHandle + public struct GameCardHandle : IEquatable { - public int Value; + internal readonly int Value; + + public GameCardHandle(int value) + { + Value = value; + } + + public override bool Equals(object obj) => obj is GameCardHandle handle && Equals(handle); + public bool Equals(GameCardHandle other) => Value == other.Value; + public override int GetHashCode() => Value.GetHashCode(); + public static bool operator ==(GameCardHandle left, GameCardHandle right) => left.Equals(right); + public static bool operator !=(GameCardHandle left, GameCardHandle right) => !(left == right); } } diff --git a/src/LibHac/FsService/GameCardInfo.cs b/src/LibHac/FsService/GameCardInfo.cs new file mode 100644 index 00000000..2047473d --- /dev/null +++ b/src/LibHac/FsService/GameCardInfo.cs @@ -0,0 +1,18 @@ +using LibHac.Fs; + +namespace LibHac.FsService +{ + internal class GameCardInfo + { + public byte[] RootPartitionHeaderHash { get; } = new byte[0x20]; + public ulong PackageId { get; set; } + public long Size { get; set; } + public long RootPartitionOffset { get; set; } + public long RootPartitionHeaderSize { get; set; } + public long SecureAreaOffset { get; set; } + public long SecureAreaSize { get; set; } + public int UpdateVersion { get; set; } + public ulong UpdateTitleId { get; set; } + public GameCardAttribute Attribute { get; set; } + } +} diff --git a/src/LibHac/Horizon.cs b/src/LibHac/Horizon.cs index d93fc1df..302acee5 100644 --- a/src/LibHac/Horizon.cs +++ b/src/LibHac/Horizon.cs @@ -20,14 +20,19 @@ namespace LibHac Fs = new FileSystemClient(timer); } - public void InitializeFileSystemServer(FileSystemCreators fsCreators) + public void InitializeFileSystemServer(FileSystemCreators fsCreators, IDeviceOperator deviceOperator) { if (FsSrv != null) return; lock (_initLocker) { if (FsSrv != null) return; - FsSrv = new FileSystemServer(fsCreators); + + var config = new FileSystemServerConfig(); + config.FsCreators = fsCreators; + config.DeviceOperator = deviceOperator; + + FsSrv = new FileSystemServer(config); } } } diff --git a/src/LibHac/XciHeader.cs b/src/LibHac/XciHeader.cs index f945c8a3..361dcad8 100644 --- a/src/LibHac/XciHeader.cs +++ b/src/LibHac/XciHeader.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Text; +using LibHac.Fs; namespace LibHac { @@ -36,9 +37,9 @@ namespace LibHac public int BackupAreaStartPage { get; set; } public byte KekIndex { get; set; } public byte TitleKeyDecIndex { get; set; } - public RomSize RomSize { get; set; } + public GameCardSize GameCardSize { get; set; } public byte CardHeaderVersion { get; set; } - public XciFlags Flags { get; set; } + public GameCardAttribute Flags { get; set; } public ulong PackageId { get; set; } public long ValidDataEndPage { get; set; } public byte[] AesCbcIv { get; set; } @@ -62,8 +63,9 @@ namespace LibHac public byte[] UppHash { get; set; } public ulong UppId { get; set; } - public Validity SignatureValidity { get; set; } + public byte[] ImageHash { get; } + public Validity SignatureValidity { get; set; } public Validity PartitionFsHeaderValidity { get; set; } public XciHeader(Keyset keyset, Stream stream) @@ -88,9 +90,9 @@ namespace LibHac byte keyIndex = reader.ReadByte(); KekIndex = (byte)(keyIndex >> 4); TitleKeyDecIndex = (byte)(keyIndex & 7); - RomSize = (RomSize)reader.ReadByte(); + GameCardSize = (GameCardSize)reader.ReadByte(); CardHeaderVersion = reader.ReadByte(); - Flags = (XciFlags)reader.ReadByte(); + Flags = (GameCardAttribute)reader.ReadByte(); PackageId = reader.ReadUInt64(); ValidDataEndPage = reader.ReadInt64(); AesCbcIv = reader.ReadBytes(Crypto.Aes128Size); @@ -104,7 +106,7 @@ namespace LibHac SelKey = reader.ReadInt32(); LimAreaPage = reader.ReadInt32(); - if (!keyset.XciHeaderKey.IsEmpty()) + if (keyset != null && !keyset.XciHeaderKey.IsEmpty()) { byte[] encHeader = reader.ReadBytes(EncryptedHeaderSize); var decHeader = new byte[EncryptedHeaderSize]; @@ -126,30 +128,14 @@ namespace LibHac } } + ImageHash = Crypto.ComputeSha256(sigData, 0, sigData.Length); + reader.BaseStream.Position = RootPartitionOffset; PartitionFsHeaderValidity = Crypto.CheckMemoryHashTable(reader.ReadBytes((int)RootPartitionHeaderSize), RootPartitionHeaderHash, 0, (int)RootPartitionHeaderSize); } } } - public enum RomSize - { - Size1Gb = 0xFA, - Size2Gb = 0xF8, - Size4Gb = 0xF0, - Size8Gb = 0xE0, - Size16Gb = 0xE1, - Size32Gb = 0xE2 - } - - [Flags] - public enum XciFlags - { - AutoBoot = 1 << 0, - HistoryErase = 1 << 1, - RepairTool = 1 << 2 - } - public enum CardClockRate { ClockRate25 = 10551312, diff --git a/src/hactoolnet/ProcessXci.cs b/src/hactoolnet/ProcessXci.cs index 03841cca..43c36f48 100644 --- a/src/hactoolnet/ProcessXci.cs +++ b/src/hactoolnet/ProcessXci.cs @@ -149,7 +149,7 @@ namespace hactoolnet PrintItem(sb, colLen, "Magic:", xci.Header.Magic); PrintItem(sb, colLen, $"Header Signature{xci.Header.SignatureValidity.GetValidityString()}:", xci.Header.Signature); PrintItem(sb, colLen, $"Header Hash{xci.Header.PartitionFsHeaderValidity.GetValidityString()}:", xci.Header.RootPartitionHeaderHash); - PrintItem(sb, colLen, "Cartridge Type:", GetCartridgeType(xci.Header.RomSize)); + PrintItem(sb, colLen, "Cartridge Type:", GetCartridgeType(xci.Header.GameCardSize)); PrintItem(sb, colLen, "Cartridge Size:", $"0x{Util.MediaToReal(xci.Header.ValidDataEndPage + 1):x12}"); PrintItem(sb, colLen, "Header IV:", xci.Header.AesCbcIv); @@ -192,16 +192,16 @@ namespace hactoolnet } } - private static string GetCartridgeType(RomSize size) + private static string GetCartridgeType(GameCardSize size) { switch (size) { - case RomSize.Size1Gb: return "1GB"; - case RomSize.Size2Gb: return "2GB"; - case RomSize.Size4Gb: return "4GB"; - case RomSize.Size8Gb: return "8GB"; - case RomSize.Size16Gb: return "16GB"; - case RomSize.Size32Gb: return "32GB"; + case GameCardSize.Size1Gb: return "1GB"; + case GameCardSize.Size2Gb: return "2GB"; + case GameCardSize.Size4Gb: return "4GB"; + case GameCardSize.Size8Gb: return "8GB"; + case GameCardSize.Size16Gb: return "16GB"; + case GameCardSize.Size32Gb: return "32GB"; default: return string.Empty; } } From b517085e92ef9e7554ad3ada4b8377c4ba949ebb Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 7 Oct 2019 19:01:53 -0500 Subject: [PATCH 38/46] Add DefaultFsServerObjects for creating a default server instance --- .../FsService/Creators/FileSystemCreators.cs | 24 +------------ .../FsService/DefaultFsServerObjects.cs | 34 +++++++++++++++++++ src/LibHac/FsService/EmulatedGameCard.cs | 9 ++++- 3 files changed, 43 insertions(+), 24 deletions(-) create mode 100644 src/LibHac/FsService/DefaultFsServerObjects.cs diff --git a/src/LibHac/FsService/Creators/FileSystemCreators.cs b/src/LibHac/FsService/Creators/FileSystemCreators.cs index 08b35243..c9c048a9 100644 --- a/src/LibHac/FsService/Creators/FileSystemCreators.cs +++ b/src/LibHac/FsService/Creators/FileSystemCreators.cs @@ -1,6 +1,4 @@ -using LibHac.Fs; - -namespace LibHac.FsService.Creators +namespace LibHac.FsService.Creators { public class FileSystemCreators { @@ -20,25 +18,5 @@ namespace LibHac.FsService.Creators public IMemoryStorageCreator MemoryStorageCreator { get; set; } public IBuiltInStorageFileSystemCreator BuiltInStorageFileSystemCreator { get; set; } public ISdFileSystemCreator SdFileSystemCreator { get; set; } - - public IDeviceOperator DeviceOperator { get; set; } - - public static (FileSystemCreators fsCreators, EmulatedGameCard gameCard) GetDefaultEmulatedCreators( - IFileSystem rootFileSystem, Keyset keyset) - { - var creators = new FileSystemCreators(); - var gameCard = new EmulatedGameCard(); - - creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); - creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(keyset); - creators.GameCardStorageCreator = new EmulatedGameCardStorageCreator(gameCard); - creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keyset); - creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem); - creators.SdFileSystemCreator = new EmulatedSdFileSystemCreator(rootFileSystem); - - creators.DeviceOperator = new EmulatedDeviceOperator(gameCard); - - return (creators, gameCard); - } } } diff --git a/src/LibHac/FsService/DefaultFsServerObjects.cs b/src/LibHac/FsService/DefaultFsServerObjects.cs new file mode 100644 index 00000000..9ea1f4c2 --- /dev/null +++ b/src/LibHac/FsService/DefaultFsServerObjects.cs @@ -0,0 +1,34 @@ +using LibHac.Fs; +using LibHac.FsService.Creators; + +namespace LibHac.FsService +{ + public class DefaultFsServerObjects + { + public FileSystemCreators FsCreators { get; set; } + public IDeviceOperator DeviceOperator { get; set; } + public EmulatedGameCard GameCard { get; set; } + + public static DefaultFsServerObjects GetDefaultEmulatedCreators(IFileSystem rootFileSystem, Keyset keyset) + { + var creators = new FileSystemCreators(); + var gameCard = new EmulatedGameCard(keyset); + + creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); + creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(keyset); + creators.GameCardStorageCreator = new EmulatedGameCardStorageCreator(gameCard); + creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keyset); + creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem); + creators.SdFileSystemCreator = new EmulatedSdFileSystemCreator(rootFileSystem); + + var deviceOperator = new EmulatedDeviceOperator(gameCard); + + return new DefaultFsServerObjects + { + FsCreators = creators, + DeviceOperator = deviceOperator, + GameCard = gameCard + }; + } + } +} diff --git a/src/LibHac/FsService/EmulatedGameCard.cs b/src/LibHac/FsService/EmulatedGameCard.cs index e3e8ec25..121fc03c 100644 --- a/src/LibHac/FsService/EmulatedGameCard.cs +++ b/src/LibHac/FsService/EmulatedGameCard.cs @@ -9,7 +9,14 @@ namespace LibHac.FsService private IStorage CardImageStorage { get; set; } private int Handle { get; set; } private XciHeader CardHeader { get; set; } + private Keyset Keyset { get; set; } + public EmulatedGameCard() { } + + public EmulatedGameCard(Keyset keyset) + { + Keyset = keyset; + } public GameCardHandle GetGameCardHandle() { return new GameCardHandle(Handle); @@ -31,7 +38,7 @@ namespace LibHac.FsService CardImageStorage = cardImageStorage; - CardHeader = new XciHeader(null, cardImageStorage.AsStream()); + CardHeader = new XciHeader(Keyset, cardImageStorage.AsStream()); } public void RemoveGameCard() From 6ed1f1297d20af8262ec83033bdbc5827e953a8c Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 8 Oct 2019 11:29:33 -0500 Subject: [PATCH 39/46] Make GameCardHandle.Value public --- src/LibHac/FsService/GameCardHandle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LibHac/FsService/GameCardHandle.cs b/src/LibHac/FsService/GameCardHandle.cs index 21214ad8..0144fbc2 100644 --- a/src/LibHac/FsService/GameCardHandle.cs +++ b/src/LibHac/FsService/GameCardHandle.cs @@ -4,7 +4,7 @@ namespace LibHac.FsService { public struct GameCardHandle : IEquatable { - internal readonly int Value; + public readonly int Value; public GameCardHandle(int value) { From 089b5b4f63b562a07d1ddb408d7248117f9980f7 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 8 Oct 2019 20:39:07 -0500 Subject: [PATCH 40/46] Add EmulatedGameCardFsCreator --- src/LibHac/Fs/GameCard.cs | 51 +++++++++++++++++++ .../Creators/EmulatedGameCardFsCreator.cs | 34 +++++++++++++ .../EmulatedGameCardStorageCreator.cs | 2 +- .../Creators/EmulatedSdFileSystemCreator.cs | 2 + .../FsService/DefaultFsServerObjects.cs | 5 +- src/LibHac/FsService/EmulatedGameCard.cs | 15 +++++- src/LibHac/FsService/FileSystemProxy.cs | 7 ++- src/LibHac/FsService/FileSystemProxyCore.cs | 6 +++ 8 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 src/LibHac/FsService/Creators/EmulatedGameCardFsCreator.cs 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); From 54950c9b68034952e2e81d3ec4166cdf66e8a11e Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Thu, 10 Oct 2019 19:01:46 -0500 Subject: [PATCH 41/46] Handle more errors in LocalFileSystem --- src/LibHac/Common/HResult.cs | 44 ++++ src/LibHac/Fs/IAttributeFileSystem.cs | 2 +- src/LibHac/Fs/ResultFs.cs | 4 + .../FsSystem/ConcatenationFileSystem.cs | 3 +- src/LibHac/FsSystem/LocalDirectory.cs | 27 +- src/LibHac/FsSystem/LocalFile.cs | 69 +++-- src/LibHac/FsSystem/LocalFileSystem.cs | 243 +++++++++--------- 7 files changed, 211 insertions(+), 181 deletions(-) create mode 100644 src/LibHac/Common/HResult.cs diff --git a/src/LibHac/Common/HResult.cs b/src/LibHac/Common/HResult.cs new file mode 100644 index 00000000..728c6e21 --- /dev/null +++ b/src/LibHac/Common/HResult.cs @@ -0,0 +1,44 @@ +using System.Diagnostics.CodeAnalysis; +using LibHac.Fs; + +namespace LibHac.Common +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + internal static class HResult + { + public const int ERROR_FILE_NOT_FOUND = unchecked((int)0x80070002); + public const int ERROR_PATH_NOT_FOUND = unchecked((int)0x80070003); + public const int ERROR_ACCESS_DENIED = unchecked((int)0x80070005); + public const int ERROR_SHARING_VIOLATION = unchecked((int)0x80070020); + public const int ERROR_HANDLE_EOF = unchecked((int)0x80070026); + public const int ERROR_HANDLE_DISK_FULL = unchecked((int)0x80070027); + public const int ERROR_FILE_EXISTS = unchecked((int)0x80070050); + public const int ERROR_DISK_FULL = unchecked((int)0x80070070); + public const int ERROR_INVALID_NAME = unchecked((int)0x8007007B); + public const int ERROR_DIR_NOT_EMPTY = unchecked((int)0x80070091); + public const int ERROR_ALREADY_EXISTS = unchecked((int)0x800700B7); + public const int ERROR_DIRECTORY = unchecked((int)0x8007010B); + public const int ERROR_SPACES_NOT_ENOUGH_DRIVES = unchecked((int)0x80E7000B); + + public static Result HResultToHorizonResult(int hResult) + { + return hResult switch + { + ERROR_FILE_NOT_FOUND => ResultFs.PathNotFound, + ERROR_PATH_NOT_FOUND => ResultFs.PathNotFound, + ERROR_ACCESS_DENIED => ResultFs.TargetLocked, + ERROR_SHARING_VIOLATION => ResultFs.TargetLocked, + ERROR_HANDLE_EOF => ResultFs.ValueOutOfRange, + ERROR_HANDLE_DISK_FULL => ResultFs.InsufficientFreeSpace, + ERROR_FILE_EXISTS => ResultFs.PathAlreadyExists, + ERROR_DISK_FULL => ResultFs.InsufficientFreeSpace, + ERROR_INVALID_NAME => ResultFs.PathNotFound, + ERROR_DIR_NOT_EMPTY => ResultFs.DirectoryNotEmpty, + ERROR_ALREADY_EXISTS => ResultFs.PathAlreadyExists, + ERROR_DIRECTORY => ResultFs.PathNotFound, + ERROR_SPACES_NOT_ENOUGH_DRIVES => ResultFs.InsufficientFreeSpace, + _ => ResultFs.UnknownHostFileSystemError + }; + } + } +} diff --git a/src/LibHac/Fs/IAttributeFileSystem.cs b/src/LibHac/Fs/IAttributeFileSystem.cs index 676a266e..1936e8db 100644 --- a/src/LibHac/Fs/IAttributeFileSystem.cs +++ b/src/LibHac/Fs/IAttributeFileSystem.cs @@ -5,6 +5,6 @@ Result CreateDirectory(string path, NxFileAttributes archiveAttribute); Result GetFileAttributes(string path, out NxFileAttributes attributes); Result SetFileAttributes(string path, NxFileAttributes attributes); - long GetFileSize(string path); + Result GetFileSize(out long fileSize, string path); } } diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 1922b40e..75a6a0ba 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -75,6 +75,10 @@ public static Result Result4812 => new Result(ModuleFs, 4812); + public static Result UnexpectedErrorInHostFileFlush => new Result(ModuleFs, 5307); + public static Result UnexpectedErrorInHostFileGetSize => new Result(ModuleFs, 5308); + public static Result UnknownHostFileSystemError => new Result(ModuleFs, 5309); + public static Result PreconditionViolation => new Result(ModuleFs, 6000); public static Result InvalidArgument => new Result(ModuleFs, 6001); public static Result InvalidPath => new Result(ModuleFs, 6002); diff --git a/src/LibHac/FsSystem/ConcatenationFileSystem.cs b/src/LibHac/FsSystem/ConcatenationFileSystem.cs index 5de0cf13..5c60d594 100644 --- a/src/LibHac/FsSystem/ConcatenationFileSystem.cs +++ b/src/LibHac/FsSystem/ConcatenationFileSystem.cs @@ -349,7 +349,8 @@ namespace LibHac.FsSystem for (int i = 0; i < fileCount; i++) { - size += BaseFileSystem.GetFileSize(GetSubFilePath(path, i)); + BaseFileSystem.GetFileSize(out long fileSize, GetSubFilePath(path, i)).ThrowIfFailure(); + size += fileSize; } return size; diff --git a/src/LibHac/FsSystem/LocalDirectory.cs b/src/LibHac/FsSystem/LocalDirectory.cs index c49b16ab..f7cde12b 100644 --- a/src/LibHac/FsSystem/LocalDirectory.cs +++ b/src/LibHac/FsSystem/LocalDirectory.cs @@ -9,33 +9,16 @@ namespace LibHac.FsSystem { public class LocalDirectory : IDirectory { - private string LocalPath { get; } private OpenDirectoryMode Mode { get; } private DirectoryInfo DirInfo { get; } private IEnumerator EntryEnumerator { get; } - - public LocalDirectory(LocalFileSystem fs, string path, OpenDirectoryMode mode) + + public LocalDirectory(IEnumerator entryEnumerator, DirectoryInfo dirInfo, + OpenDirectoryMode mode) { - LocalPath = fs.ResolveLocalPath(path); + EntryEnumerator = entryEnumerator; + DirInfo = dirInfo; Mode = mode; - - try - { - DirInfo = new DirectoryInfo(LocalPath); - } - catch (Exception ex) when (ex is ArgumentNullException || ex is ArgumentException || - ex is PathTooLongException) - { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; - } - - if (!DirInfo.Exists) - { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); - } - - EntryEnumerator = DirInfo.EnumerateFileSystemInfos().GetEnumerator(); } public Result Read(out long entriesRead, Span entryBuffer) diff --git a/src/LibHac/FsSystem/LocalFile.cs b/src/LibHac/FsSystem/LocalFile.cs index b4f02612..6a56d1d8 100644 --- a/src/LibHac/FsSystem/LocalFile.cs +++ b/src/LibHac/FsSystem/LocalFile.cs @@ -1,22 +1,29 @@ using System; using System.IO; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem { public class LocalFile : FileBase { - private const int ErrorHandleDiskFull = unchecked((int)0x80070027); - private const int ErrorDiskFull = unchecked((int)0x80070070); - private FileStream Stream { get; } private StreamFile File { get; } private OpenMode Mode { get; } public LocalFile(string path, OpenMode mode) { + LocalFileSystem.OpenFileInternal(out FileStream stream, path, mode).ThrowIfFailure(); + Mode = mode; - Stream = OpenFile(path, mode); + Stream = stream; + File = new StreamFile(Stream, mode); + } + + public LocalFile(FileStream stream, OpenMode mode) + { + Mode = mode; + Stream = stream; File = new StreamFile(Stream, mode); } @@ -40,12 +47,27 @@ namespace LibHac.FsSystem public override Result FlushImpl() { - return File.Flush(); + try + { + return File.Flush(); + } + catch (Exception ex) when (ex.HResult < 0) + { + return ResultFs.UnexpectedErrorInHostFileFlush.Log(); + } } public override Result GetSizeImpl(out long size) { - return File.GetSize(out size); + try + { + return File.GetSize(out size); + } + catch (Exception ex) when (ex.HResult < 0) + { + size = default; + return ResultFs.UnexpectedErrorInHostFileGetSize.Log(); + } } public override Result SetSizeImpl(long size) @@ -54,9 +76,9 @@ namespace LibHac.FsSystem { File.SetSize(size); } - catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) + catch (Exception ex) when (ex.HResult < 0) { - return ResultFs.InsufficientFreeSpace.Log(); + return HResult.HResultToHorizonResult(ex.HResult).Log(); } return Result.Success; @@ -71,36 +93,5 @@ namespace LibHac.FsSystem Stream?.Dispose(); } - - private static FileAccess GetFileAccess(OpenMode mode) - { - // FileAccess and OpenMode have the same flags - return (FileAccess)(mode & OpenMode.ReadWrite); - } - - private static FileShare GetFileShare(OpenMode mode) - { - return mode.HasFlag(OpenMode.Write) ? FileShare.Read : FileShare.ReadWrite; - } - - private static FileStream OpenFile(string path, OpenMode mode) - { - try - { - return new FileStream(path, FileMode.Open, GetFileAccess(mode), GetFileShare(mode)); - } - catch (Exception ex) when (ex is ArgumentNullException || ex is ArgumentException || - ex is PathTooLongException || ex is DirectoryNotFoundException || - ex is FileNotFoundException || ex is NotSupportedException) - { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; - } - catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) - { - // todo: Should a HorizonResultException be thrown? - throw; - } - } } } diff --git a/src/LibHac/FsSystem/LocalFileSystem.cs b/src/LibHac/FsSystem/LocalFileSystem.cs index 13d39665..69425b06 100644 --- a/src/LibHac/FsSystem/LocalFileSystem.cs +++ b/src/LibHac/FsSystem/LocalFileSystem.cs @@ -1,17 +1,13 @@ using System; +using System.Collections.Generic; using System.IO; -using System.Security; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem { public class LocalFileSystem : IAttributeFileSystem { - private const int ErrorHandleDiskFull = unchecked((int)0x80070027); - private const int ErrorFileExists = unchecked((int)0x80070050); - private const int ErrorDiskFull = unchecked((int)0x80070070); - private const int ErrorDirNotEmpty = unchecked((int)0x80070091); - private string BasePath { get; } /// @@ -36,9 +32,12 @@ namespace LibHac.FsSystem public Result GetFileAttributes(string path, out NxFileAttributes attributes) { + attributes = default; + string localPath = ResolveLocalPath(PathTools.Normalize(path)); - FileInfo info = GetFileInfo(localPath); + Result rc = GetFileInfo(out FileInfo info, localPath); + if (rc.IsFailure()) return rc; if (info.Attributes == (FileAttributes)(-1)) { @@ -54,7 +53,8 @@ namespace LibHac.FsSystem { string localPath = ResolveLocalPath(PathTools.Normalize(path)); - FileInfo info = GetFileInfo(localPath); + Result rc = GetFileInfo(out FileInfo info, localPath); + if (rc.IsFailure()) return rc; if (info.Attributes == (FileAttributes)(-1)) { @@ -76,12 +76,15 @@ namespace LibHac.FsSystem return Result.Success; } - public long GetFileSize(string path) + public Result GetFileSize(out long fileSize, string path) { + fileSize = default; string localPath = ResolveLocalPath(PathTools.Normalize(path)); - FileInfo info = GetFileInfo(localPath); - return GetSizeInternal(info); + Result rc = GetFileInfo(out FileInfo info, localPath); + if (rc.IsFailure()) return rc; + + return GetSizeInternal(out fileSize, info); } public Result CreateDirectory(string path) @@ -93,7 +96,8 @@ namespace LibHac.FsSystem { string localPath = ResolveLocalPath(PathTools.Normalize(path)); - DirectoryInfo dir = GetDirInfo(localPath); + Result rc = GetDirInfo(out DirectoryInfo dir, localPath); + if (rc.IsFailure()) return rc; if (dir.Exists) { @@ -112,7 +116,8 @@ namespace LibHac.FsSystem { string localPath = ResolveLocalPath(PathTools.Normalize(path)); - FileInfo file = GetFileInfo(localPath); + Result rc = GetFileInfo(out FileInfo file, localPath); + if (rc.IsFailure()) return rc; if (file.Exists) { @@ -124,7 +129,7 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - Result rc = CreateFileInternal(out FileStream stream, file); + rc = CreateFileInternal(out FileStream stream, file); using (stream) { @@ -138,7 +143,8 @@ namespace LibHac.FsSystem { string localPath = ResolveLocalPath(PathTools.Normalize(path)); - DirectoryInfo dir = GetDirInfo(localPath); + Result rc = GetDirInfo(out DirectoryInfo dir, localPath); + if (rc.IsFailure()) return rc; return DeleteDirectoryInternal(dir, false); } @@ -147,7 +153,8 @@ namespace LibHac.FsSystem { string localPath = ResolveLocalPath(PathTools.Normalize(path)); - DirectoryInfo dir = GetDirInfo(localPath); + Result rc = GetDirInfo(out DirectoryInfo dir, localPath); + if (rc.IsFailure()) return rc; return DeleteDirectoryInternal(dir, true); } @@ -158,13 +165,19 @@ namespace LibHac.FsSystem foreach (string file in Directory.EnumerateFiles(localPath)) { - Result rc = DeleteFileInternal(GetFileInfo(file)); + Result rc = GetFileInfo(out FileInfo fileInfo, file); + if (rc.IsFailure()) return rc; + + rc = DeleteFileInternal(fileInfo); if (rc.IsFailure()) return rc; } foreach (string dir in Directory.EnumerateDirectories(localPath)) { - Result rc = DeleteDirectoryInternal(GetDirInfo(dir), true); + Result rc = GetDirInfo(out DirectoryInfo dirInfo, dir); + if (rc.IsFailure()) return rc; + + rc = DeleteDirectoryInternal(dirInfo, true); if (rc.IsFailure()) return rc; } @@ -175,27 +188,36 @@ namespace LibHac.FsSystem { string localPath = ResolveLocalPath(PathTools.Normalize(path)); - FileInfo file = GetFileInfo(localPath); + Result rc = GetFileInfo(out FileInfo file, localPath); + if (rc.IsFailure()) return rc; return DeleteFileInternal(file); } public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { - // Getting the local path is done in the LocalDirectory constructor - path = PathTools.Normalize(path); directory = default; + string localPath = ResolveLocalPath(PathTools.Normalize(path)); - Result rc = GetEntryType(out DirectoryEntryType entryType, path); + Result rc = GetDirInfo(out DirectoryInfo dirInfo, localPath); if (rc.IsFailure()) return rc; - if (entryType == DirectoryEntryType.File) + if (!dirInfo.Attributes.HasFlag(FileAttributes.Directory)) { return ResultFs.PathNotFound.Log(); } - directory = new LocalDirectory(this, path, mode); - return Result.Success; + try + { + IEnumerator entryEnumerator = dirInfo.EnumerateFileSystemInfos().GetEnumerator(); + + directory = new LocalDirectory(entryEnumerator, dirInfo, mode); + return Result.Success; + } + catch (Exception ex) when (ex.HResult < 0) + { + return HResult.HResultToHorizonResult(ex.HResult).Log(); + } } public Result OpenFile(out IFile file, string path, OpenMode mode) @@ -211,7 +233,10 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - file = new LocalFile(localPath, mode); + rc = OpenFileInternal(out FileStream fileStream, localPath, mode); + if (rc.IsFailure()) return rc; + + file = new LocalFile(fileStream, mode); return Result.Success; } @@ -229,8 +254,11 @@ namespace LibHac.FsSystem ThrowHelper.ThrowResult(ResultFs.DestinationIsSubPathOfSource); } - DirectoryInfo srcDir = GetDirInfo(ResolveLocalPath(oldPath)); - DirectoryInfo dstDir = GetDirInfo(ResolveLocalPath(newPath)); + Result rc = GetDirInfo(out DirectoryInfo srcDir, ResolveLocalPath(oldPath)); + if (rc.IsFailure()) return rc; + + rc = GetDirInfo(out DirectoryInfo dstDir, ResolveLocalPath(newPath)); + if (rc.IsFailure()) return rc; return RenameDirInternal(srcDir, dstDir); } @@ -243,17 +271,22 @@ namespace LibHac.FsSystem // Official FS behavior is to do nothing in this case if (srcLocalPath == dstLocalPath) return Result.Success; - FileInfo srcFile = GetFileInfo(srcLocalPath); - FileInfo dstFile = GetFileInfo(dstLocalPath); + Result rc = GetFileInfo(out FileInfo srcFile, srcLocalPath); + if (rc.IsFailure()) return rc; + + rc = GetFileInfo(out FileInfo dstFile, dstLocalPath); + if (rc.IsFailure()) return rc; return RenameFileInternal(srcFile, dstFile); } public Result GetEntryType(out DirectoryEntryType entryType, string path) { + entryType = default; string localPath = ResolveLocalPath(PathTools.Normalize(path)); - DirectoryInfo dir = GetDirInfo(localPath); + Result rc = GetDirInfo(out DirectoryInfo dir, localPath); + if (rc.IsFailure()) return rc; if (dir.Exists) { @@ -261,7 +294,8 @@ namespace LibHac.FsSystem return Result.Success; } - FileInfo file = GetFileInfo(localPath); + rc = GetFileInfo(out FileInfo file, localPath); + if (rc.IsFailure()) return rc; if (file.Exists) { @@ -278,7 +312,10 @@ namespace LibHac.FsSystem timeStamp = default; string localPath = ResolveLocalPath(PathTools.Normalize(path)); - if (!GetFileInfo(localPath).Exists) return ResultFs.PathNotFound.Log(); + Result rc = GetFileInfo(out FileInfo file, localPath); + if (rc.IsFailure()) return rc; + + if (!file.Exists) return ResultFs.PathNotFound.Log(); timeStamp.Created = new DateTimeOffset(File.GetCreationTime(localPath)).ToUnixTimeSeconds(); timeStamp.Accessed = new DateTimeOffset(File.GetLastAccessTime(localPath)).ToUnixTimeSeconds(); @@ -309,21 +346,42 @@ namespace LibHac.FsSystem return ResultFs.UnsupportedOperation.Log(); } - private static long GetSizeInternal(FileInfo file) + internal static FileAccess GetFileAccess(OpenMode mode) + { + // FileAccess and OpenMode have the same flags + return (FileAccess)(mode & OpenMode.ReadWrite); + } + + internal static FileShare GetFileShare(OpenMode mode) + { + return mode.HasFlag(OpenMode.Write) ? FileShare.Read : FileShare.ReadWrite; + } + + internal static Result OpenFileInternal(out FileStream stream, string path, OpenMode mode) { try { - return file.Length; + stream = new FileStream(path, FileMode.Open, GetFileAccess(mode), GetFileShare(mode)); + return Result.Success; } - catch (FileNotFoundException ex) + catch (Exception ex) when (ex.HResult < 0) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + stream = default; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } - catch (Exception ex) when (ex is SecurityException || ex is UnauthorizedAccessException) + } + + private static Result GetSizeInternal(out long fileSize, FileInfo file) + { + try { - // todo: Should a HorizonResultException be thrown? - throw; + fileSize = file.Length; + return Result.Success; + } + catch (Exception ex) when (ex.HResult < 0) + { + fileSize = default; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } } @@ -335,22 +393,9 @@ namespace LibHac.FsSystem { file = new FileStream(fileInfo.FullName, FileMode.CreateNew, FileAccess.ReadWrite); } - catch (DirectoryNotFoundException) + catch (Exception ex) when (ex.HResult < 0) { - return ResultFs.PathNotFound.Log(); - } - catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) - { - return ResultFs.InsufficientFreeSpace.Log(); - } - catch (IOException ex) when (ex.HResult == ErrorFileExists) - { - return ResultFs.PathAlreadyExists.Log(); - } - catch (Exception ex) when (ex is SecurityException || ex is UnauthorizedAccessException) - { - // todo: What Result value should be returned? - throw; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } return Result.Success; @@ -362,9 +407,9 @@ namespace LibHac.FsSystem { stream.SetLength(size); } - catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) + catch (Exception ex) when (ex.HResult < 0) { - return ResultFs.InsufficientFreeSpace.Log(); + return HResult.HResultToHorizonResult(ex.HResult).Log(); } return Result.Success; @@ -378,18 +423,9 @@ namespace LibHac.FsSystem { dir.Delete(recursive); } - catch (DirectoryNotFoundException) + catch (Exception ex) when (ex.HResult < 0) { - return ResultFs.PathNotFound.Log(); - } - catch (IOException ex) when (ex.HResult == ErrorDirNotEmpty) - { - return ResultFs.DirectoryNotEmpty.Log(); - } - catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) - { - // todo: What Result value should be returned? - throw; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } EnsureDeleted(dir); @@ -405,18 +441,9 @@ namespace LibHac.FsSystem { file.Delete(); } - catch (DirectoryNotFoundException) + catch (Exception ex) when (ex.HResult < 0) { - return ResultFs.PathNotFound.Log(); - } - catch (IOException ex) when (ex.HResult == ErrorDirNotEmpty) - { - return ResultFs.DirectoryNotEmpty.Log(); - } - catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) - { - // todo: What Result value should be returned? - throw; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } EnsureDeleted(file); @@ -436,18 +463,9 @@ namespace LibHac.FsSystem dir.Attributes |= FileAttributes.Archive; } } - catch (DirectoryNotFoundException) + catch (Exception ex) when (ex.HResult < 0) { - return ResultFs.PathNotFound.Log(); - } - catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) - { - return ResultFs.InsufficientFreeSpace.Log(); - } - catch (Exception ex) when (ex is SecurityException || ex is UnauthorizedAccessException) - { - // todo: What Result value should be returned? - throw; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } return Result.Success; @@ -462,14 +480,9 @@ namespace LibHac.FsSystem { source.MoveTo(dest.FullName); } - catch (DirectoryNotFoundException) + catch (Exception ex) when (ex.HResult < 0) { - return ResultFs.PathNotFound.Log(); - } - catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) - { - // todo: What Result value should be returned? - throw; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } return Result.Success; @@ -484,46 +497,40 @@ namespace LibHac.FsSystem { source.MoveTo(dest.FullName); } - catch (DirectoryNotFoundException) + catch (Exception ex) when (ex.HResult < 0) { - return ResultFs.PathNotFound.Log(); - } - catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) - { - // todo: What Result value should be returned? - throw; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } return Result.Success; } - // GetFileInfo and GetDirInfo detect invalid paths - private static FileInfo GetFileInfo(string path) + private static Result GetFileInfo(out FileInfo fileInfo, string path) { try { - return new FileInfo(path); + fileInfo = new FileInfo(path); + return Result.Success; } - catch (Exception ex) when (ex is ArgumentNullException || ex is ArgumentException || - ex is PathTooLongException) + catch (Exception ex) when (ex.HResult < 0) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + fileInfo = default; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } } - private static DirectoryInfo GetDirInfo(string path) + private static Result GetDirInfo(out DirectoryInfo directoryInfo, string path) { try { - return new DirectoryInfo(path); + directoryInfo = new DirectoryInfo(path); + return Result.Success; } - catch (Exception ex) when (ex is ArgumentNullException || ex is ArgumentException || - ex is PathTooLongException) + catch (Exception ex) when (ex.HResult < 0) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + directoryInfo = default; + return HResult.HResultToHorizonResult(ex.HResult).Log(); } } From bfc343e80131261e2f6d359ea9efa323fddfe372 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 11 Oct 2019 12:53:29 -0500 Subject: [PATCH 42/46] Add some validation to StorageBase --- src/LibHac/Fs/FileBase.cs | 2 +- src/LibHac/Fs/FileHandleStorage.cs | 14 ++-- src/LibHac/Fs/FileSystemClient.AccessLog.cs | 4 +- src/LibHac/Fs/ResultFs.cs | 2 +- src/LibHac/Fs/SaveData.cs | 4 +- src/LibHac/Fs/StorageBase.cs | 65 +++++++++++++++++-- src/LibHac/Fs/SubStorage2.cs | 26 ++++---- .../EmulatedGameCardStorageCreator.cs | 10 +-- src/LibHac/FsSystem/SubStorage.cs | 2 +- 9 files changed, 89 insertions(+), 40 deletions(-) diff --git a/src/LibHac/Fs/FileBase.cs b/src/LibHac/Fs/FileBase.cs index 244c8200..887dfa98 100644 --- a/src/LibHac/Fs/FileBase.cs +++ b/src/LibHac/Fs/FileBase.cs @@ -55,7 +55,7 @@ namespace LibHac.Fs public Result GetSize(out long size) { - size = 0; + size = default; if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return GetSizeImpl(out size); diff --git a/src/LibHac/Fs/FileHandleStorage.cs b/src/LibHac/Fs/FileHandleStorage.cs index 729e2d78..83c379c9 100644 --- a/src/LibHac/Fs/FileHandleStorage.cs +++ b/src/LibHac/Fs/FileHandleStorage.cs @@ -21,7 +21,7 @@ namespace LibHac.Fs FsClient = Handle.File.Parent.FsClient; } - public override Result Read(long offset, Span destination) + public override Result ReadImpl(long offset, Span destination) { lock (_locker) { @@ -30,14 +30,13 @@ namespace LibHac.Fs Result rc = UpdateSize(); if (rc.IsFailure()) return rc; - if (destination.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); if (!IsRangeValid(offset, destination.Length, FileSize)) return ResultFs.ValueOutOfRange.Log(); return FsClient.ReadFile(Handle, offset, destination); } } - public override Result Write(long offset, ReadOnlySpan source) + public override Result WriteImpl(long offset, ReadOnlySpan source) { lock (_locker) { @@ -46,26 +45,25 @@ namespace LibHac.Fs Result rc = UpdateSize(); if (rc.IsFailure()) return rc; - if (source.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); if (!IsRangeValid(offset, source.Length, FileSize)) return ResultFs.ValueOutOfRange.Log(); return FsClient.WriteFile(Handle, offset, source); } } - public override Result Flush() + public override Result FlushImpl() { return FsClient.FlushFile(Handle); } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { FileSize = InvalidSize; return FsClient.SetFileSize(Handle, size); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = default; @@ -87,7 +85,7 @@ namespace LibHac.Fs return Result.Success; } - public override void Dispose() + protected override void Dispose(bool disposing) { if (CloseHandle) { diff --git a/src/LibHac/Fs/FileSystemClient.AccessLog.cs b/src/LibHac/Fs/FileSystemClient.AccessLog.cs index e4f3bee8..f7e89383 100644 --- a/src/LibHac/Fs/FileSystemClient.AccessLog.cs +++ b/src/LibHac/Fs/FileSystemClient.AccessLog.cs @@ -205,8 +205,8 @@ namespace LibHac.Fs { None = 0, Application = 1 << 0, - Internal = 1 << 1, - All = Application | Internal + System = 1 << 1, + All = Application | System } [Flags] diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 75a6a0ba..c4b1173f 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -135,7 +135,7 @@ public static Result RemapStorageMapFull => new Result(ModuleFs, 6811); - public static Result Result6902 => new Result(ModuleFs, 6902); + public static Result SubStorageNotInitialized => new Result(ModuleFs, 6902); public static Result MountNameNotFound => new Result(ModuleFs, 6905); } } diff --git a/src/LibHac/Fs/SaveData.cs b/src/LibHac/Fs/SaveData.cs index 5ae9468d..a0bc1b21 100644 --- a/src/LibHac/Fs/SaveData.cs +++ b/src/LibHac/Fs/SaveData.cs @@ -31,7 +31,7 @@ namespace LibHac.Fs public static Result CreateSystemSaveData(this FileSystemClient fs, SaveDataSpaceId spaceId, ulong saveDataId, UserId userId, ulong ownerId, long size, long journalSize, uint flags) { - return fs.RunOperationWithAccessLog(LocalAccessLogMode.Internal, + return fs.RunOperationWithAccessLog(LocalAccessLogMode.System, () => { IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); @@ -89,7 +89,7 @@ namespace LibHac.Fs public static Result DeleteSaveData(this FileSystemClient fs, ulong saveDataId) { - return fs.RunOperationWithAccessLog(LocalAccessLogMode.Internal, + return fs.RunOperationWithAccessLog(LocalAccessLogMode.System, () => { IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); diff --git a/src/LibHac/Fs/StorageBase.cs b/src/LibHac/Fs/StorageBase.cs index 732b611f..60fe4f93 100644 --- a/src/LibHac/Fs/StorageBase.cs +++ b/src/LibHac/Fs/StorageBase.cs @@ -1,20 +1,71 @@ using System; +using System.Threading; namespace LibHac.Fs { public abstract class StorageBase : IStorage { - public abstract Result Read(long offset, Span destination); - public abstract Result Write(long offset, ReadOnlySpan source); - public abstract Result Flush(); - public abstract Result SetSize(long size); - public abstract Result GetSize(out long size); + // 0 = not disposed; 1 = disposed + private int _disposedState; + private bool IsDisposed => _disposedState != 0; - public virtual void Dispose() { } + public abstract Result ReadImpl(long offset, Span destination); + public abstract Result WriteImpl(long offset, ReadOnlySpan source); + public abstract Result FlushImpl(); + public abstract Result GetSizeImpl(out long size); + public abstract Result SetSizeImpl(long size); + + public Result Read(long offset, Span destination) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return ReadImpl(offset, destination); + } + + public Result Write(long offset, ReadOnlySpan source) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return WriteImpl(offset, source); + } + + public Result Flush() + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return FlushImpl(); + } + + public Result SetSize(long size) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return SetSizeImpl(size); + } + + public Result GetSize(out long size) + { + size = default; + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return GetSizeImpl(out size); + } + + public void Dispose() + { + // Make sure Dispose is only called once + if (Interlocked.CompareExchange(ref _disposedState, 1, 0) == 0) + { + Dispose(true); + GC.SuppressFinalize(this); + } + } + + protected virtual void Dispose(bool disposing) { } public static bool IsRangeValid(long offset, long size, long totalSize) { - return size <= totalSize && offset <= totalSize - size; + return offset >= 0 && size >= 0 && size <= totalSize && offset <= totalSize - size; } } } diff --git a/src/LibHac/Fs/SubStorage2.cs b/src/LibHac/Fs/SubStorage2.cs index e919a04e..0c9790f4 100644 --- a/src/LibHac/Fs/SubStorage2.cs +++ b/src/LibHac/Fs/SubStorage2.cs @@ -23,38 +23,38 @@ namespace LibHac.Fs Size = size; } - public override Result Read(long offset, Span destination) + public override Result ReadImpl(long offset, Span destination) { - if (BaseStorage == null) return ResultFs.Result6902.Log(); + if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); if (destination.Length == 0) return Result.Success; - if (Size < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); + if (!IsRangeValid(offset, destination.Length, Size)) return ResultFs.ValueOutOfRange.Log(); return BaseStorage.Read(Offset + offset, destination); } - public override Result Write(long offset, ReadOnlySpan source) + public override Result WriteImpl(long offset, ReadOnlySpan source) { - if (BaseStorage == null) return ResultFs.Result6902.Log(); + if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); if (source.Length == 0) return Result.Success; - if (Size < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log(); + if (!IsRangeValid(offset, source.Length, Size)) return ResultFs.ValueOutOfRange.Log(); return BaseStorage.Write(Offset + offset, source); } - public override Result Flush() + public override Result FlushImpl() { - if (BaseStorage == null) return ResultFs.Result6902.Log(); + if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); return BaseStorage.Flush(); } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { - if (BaseStorage == null) return ResultFs.Result6902.Log(); + if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); if (!IsResizable) return ResultFs.SubStorageNotResizable.Log(); - if (size < 0 || Offset < 0) return ResultFs.ValueOutOfRange.Log(); + if (size < 0 || Offset < 0) return ResultFs.InvalidSize.Log(); Result rc = BaseStorage.GetSize(out long baseSize); if (rc.IsFailure()) return rc; @@ -72,11 +72,11 @@ namespace LibHac.Fs return Result.Success; } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = default; - if (BaseStorage == null) return ResultFs.Result6902.Log(); + if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); size = Size; return Result.Success; diff --git a/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs index 96160f70..f224cb80 100644 --- a/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs @@ -87,7 +87,7 @@ namespace LibHac.FsService.Creators imageHash.CopyTo(ImageHash); } - public override Result Read(long offset, Span destination) + public override Result ReadImpl(long offset, Span destination) { // In secure mode, if Handle is old and the card's device ID and // header hash are still the same, Handle is updated to the new handle @@ -95,22 +95,22 @@ namespace LibHac.FsService.Creators return GameCard.Read(Handle, offset, destination); } - public override Result Write(long offset, ReadOnlySpan source) + public override Result WriteImpl(long offset, ReadOnlySpan source) { return ResultFs.UnsupportedOperationInRoGameCardStorageWrite.Log(); } - public override Result Flush() + public override Result FlushImpl() { return Result.Success; } - public override Result SetSize(long size) + public override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperationInRoGameCardStorageSetSize.Log(); } - public override Result GetSize(out long size) + public override Result GetSizeImpl(out long size) { size = 0; diff --git a/src/LibHac/FsSystem/SubStorage.cs b/src/LibHac/FsSystem/SubStorage.cs index c8272bd8..24d4c67d 100644 --- a/src/LibHac/FsSystem/SubStorage.cs +++ b/src/LibHac/FsSystem/SubStorage.cs @@ -62,7 +62,7 @@ namespace LibHac.FsSystem public override Result SetSize(long size) { - if (BaseStorage == null) return ResultFs.Result6902.Log(); + if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); // todo: Add IsResizable member // if (!IsResizable) return ResultFs.SubStorageNotResizable.Log(); From 162fb4e389190f0498922b357c0fd7db49d73a20 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 11 Oct 2019 12:57:09 -0500 Subject: [PATCH 43/46] Move IStorage classes to the new StorageBase --- src/LibHac/Fs/FileHandleStorage.cs | 10 +-- src/LibHac/Fs/ResultFs.cs | 6 +- src/LibHac/Fs/StorageBase.cs | 10 +-- src/LibHac/Fs/SubStorage2.cs | 10 +-- .../EmulatedGameCardStorageCreator.cs | 10 +-- src/LibHac/FsSystem/Aes128CtrExStorage.cs | 2 +- src/LibHac/FsSystem/Aes128XtsStorage.cs | 2 +- src/LibHac/FsSystem/CachedStorage.cs | 36 +++++++--- src/LibHac/FsSystem/ConcatenationStorage.cs | 42 +++++++++-- src/LibHac/FsSystem/FileStorage.cs | 6 +- ...ierarchicalIntegrityVerificationStorage.cs | 32 +++++++-- src/LibHac/FsSystem/IndirectStorage.cs | 29 ++++++-- .../FsSystem/IntegrityVerificationStorage.cs | 6 +- src/LibHac/FsSystem/LocalStorage.cs | 22 ++++-- src/LibHac/FsSystem/MemoryStorage.cs | 15 ++-- src/LibHac/FsSystem/NullStorage.cs | 18 +++-- .../FsSystem/Save/AllocationTableStorage.cs | 6 +- src/LibHac/FsSystem/Save/DuplexStorage.cs | 22 ++++-- .../Save/HierarchicalDuplexStorage.cs | 16 +++-- src/LibHac/FsSystem/Save/JournalStorage.cs | 35 +++++++-- src/LibHac/FsSystem/Save/RemapStorage.cs | 23 +++++- src/LibHac/FsSystem/SectorStorage.cs | 28 +++++--- src/LibHac/FsSystem/StorageBase.cs | 71 ------------------- src/LibHac/FsSystem/StreamStorage.cs | 30 ++++++-- src/LibHac/FsSystem/SubStorage.cs | 32 ++++++--- 25 files changed, 324 insertions(+), 195 deletions(-) delete mode 100644 src/LibHac/FsSystem/StorageBase.cs diff --git a/src/LibHac/Fs/FileHandleStorage.cs b/src/LibHac/Fs/FileHandleStorage.cs index 83c379c9..c9389681 100644 --- a/src/LibHac/Fs/FileHandleStorage.cs +++ b/src/LibHac/Fs/FileHandleStorage.cs @@ -21,7 +21,7 @@ namespace LibHac.Fs FsClient = Handle.File.Parent.FsClient; } - public override Result ReadImpl(long offset, Span destination) + protected override Result ReadImpl(long offset, Span destination) { lock (_locker) { @@ -36,7 +36,7 @@ namespace LibHac.Fs } } - public override Result WriteImpl(long offset, ReadOnlySpan source) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { lock (_locker) { @@ -51,19 +51,19 @@ namespace LibHac.Fs } } - public override Result FlushImpl() + protected override Result FlushImpl() { return FsClient.FlushFile(Handle); } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { FileSize = InvalidSize; return FsClient.SetFileSize(Handle, size); } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = default; diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index c4b1173f..ae3e247d 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -105,10 +105,10 @@ public static Result UnsupportedOperation => new Result(ModuleFs, 6300); public static Result SubStorageNotResizable => new Result(ModuleFs, 6302); - public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6302); - public static Result UnsupportedOperationInMemoryStorageSetSize => new Result(ModuleFs, 6316); - public static Result UnsupportedOperationInHierarchicalIvfcStorageSetSize => new Result(ModuleFs, 6304); + public static Result SubStorageNotResizableMiddleOfFile => new Result(ModuleFs, 6303); + public static Result UnsupportedOperationInMemoryStorageSetSize => new Result(ModuleFs, 6304); public static Result UnsupportedOperationInAesCtrExStorageWrite => new Result(ModuleFs, 6310); + public static Result UnsupportedOperationInHierarchicalIvfcStorageSetSize => new Result(ModuleFs, 6316); public static Result UnsupportedOperationInIndirectStorageWrite => new Result(ModuleFs, 6324); public static Result UnsupportedOperationInIndirectStorageSetSize => new Result(ModuleFs, 6325); public static Result UnsupportedOperationInRoGameCardStorageWrite => new Result(ModuleFs, 6350); diff --git a/src/LibHac/Fs/StorageBase.cs b/src/LibHac/Fs/StorageBase.cs index 60fe4f93..33044952 100644 --- a/src/LibHac/Fs/StorageBase.cs +++ b/src/LibHac/Fs/StorageBase.cs @@ -9,11 +9,11 @@ namespace LibHac.Fs private int _disposedState; private bool IsDisposed => _disposedState != 0; - public abstract Result ReadImpl(long offset, Span destination); - public abstract Result WriteImpl(long offset, ReadOnlySpan source); - public abstract Result FlushImpl(); - public abstract Result GetSizeImpl(out long size); - public abstract Result SetSizeImpl(long size); + protected abstract Result ReadImpl(long offset, Span destination); + protected abstract Result WriteImpl(long offset, ReadOnlySpan source); + protected abstract Result FlushImpl(); + protected abstract Result GetSizeImpl(out long size); + protected abstract Result SetSizeImpl(long size); public Result Read(long offset, Span destination) { diff --git a/src/LibHac/Fs/SubStorage2.cs b/src/LibHac/Fs/SubStorage2.cs index 0c9790f4..2cbe06a1 100644 --- a/src/LibHac/Fs/SubStorage2.cs +++ b/src/LibHac/Fs/SubStorage2.cs @@ -23,7 +23,7 @@ namespace LibHac.Fs Size = size; } - public override Result ReadImpl(long offset, Span destination) + protected override Result ReadImpl(long offset, Span destination) { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); if (destination.Length == 0) return Result.Success; @@ -33,7 +33,7 @@ namespace LibHac.Fs return BaseStorage.Read(Offset + offset, destination); } - public override Result WriteImpl(long offset, ReadOnlySpan source) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); if (source.Length == 0) return Result.Success; @@ -43,14 +43,14 @@ namespace LibHac.Fs return BaseStorage.Write(Offset + offset, source); } - public override Result FlushImpl() + protected override Result FlushImpl() { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); return BaseStorage.Flush(); } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); if (!IsResizable) return ResultFs.SubStorageNotResizable.Log(); @@ -72,7 +72,7 @@ namespace LibHac.Fs return Result.Success; } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = default; diff --git a/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs index f224cb80..c8dc4bb7 100644 --- a/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedGameCardStorageCreator.cs @@ -87,7 +87,7 @@ namespace LibHac.FsService.Creators imageHash.CopyTo(ImageHash); } - public override Result ReadImpl(long offset, Span destination) + protected override Result ReadImpl(long offset, Span destination) { // In secure mode, if Handle is old and the card's device ID and // header hash are still the same, Handle is updated to the new handle @@ -95,22 +95,22 @@ namespace LibHac.FsService.Creators return GameCard.Read(Handle, offset, destination); } - public override Result WriteImpl(long offset, ReadOnlySpan source) + protected override Result WriteImpl(long offset, ReadOnlySpan source) { return ResultFs.UnsupportedOperationInRoGameCardStorageWrite.Log(); } - public override Result FlushImpl() + protected override Result FlushImpl() { return Result.Success; } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperationInRoGameCardStorageSetSize.Log(); } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = 0; diff --git a/src/LibHac/FsSystem/Aes128CtrExStorage.cs b/src/LibHac/FsSystem/Aes128CtrExStorage.cs index d91b889b..491b7ac2 100644 --- a/src/LibHac/FsSystem/Aes128CtrExStorage.cs +++ b/src/LibHac/FsSystem/Aes128CtrExStorage.cs @@ -69,7 +69,7 @@ namespace LibHac.FsSystem return ResultFs.UnsupportedOperationInAesCtrExStorageWrite.Log(); } - public override Result Flush() + protected override Result FlushImpl() { return Result.Success; } diff --git a/src/LibHac/FsSystem/Aes128XtsStorage.cs b/src/LibHac/FsSystem/Aes128XtsStorage.cs index 865e366f..b879dc92 100644 --- a/src/LibHac/FsSystem/Aes128XtsStorage.cs +++ b/src/LibHac/FsSystem/Aes128XtsStorage.cs @@ -67,7 +67,7 @@ namespace LibHac.FsSystem return base.WriteImpl(offset, _tempBuffer.AsSpan(0, size)); } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } diff --git a/src/LibHac/FsSystem/CachedStorage.cs b/src/LibHac/FsSystem/CachedStorage.cs index bc6485fb..d3303aed 100644 --- a/src/LibHac/FsSystem/CachedStorage.cs +++ b/src/LibHac/FsSystem/CachedStorage.cs @@ -8,7 +8,8 @@ namespace LibHac.FsSystem { private IStorage BaseStorage { get; } private int BlockSize { get; } - private long _length; + private long Length { get; set; } + private bool LeaveOpen { get; } private LinkedList Blocks { get; } = new LinkedList(); private Dictionary> BlockDict { get; } = new Dictionary>(); @@ -17,9 +18,10 @@ namespace LibHac.FsSystem { BaseStorage = baseStorage; BlockSize = blockSize; - BaseStorage.GetSize(out _length).ThrowIfFailure(); + LeaveOpen = leaveOpen; - if (!leaveOpen) ToDispose.Add(BaseStorage); + BaseStorage.GetSize(out long baseSize).ThrowIfFailure(); + Length = baseSize; for (int i = 0; i < cacheSize; i++) { @@ -37,6 +39,9 @@ namespace LibHac.FsSystem long inOffset = offset; int outOffset = 0; + if (!IsRangeValid(offset, destination.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + lock (Blocks) { while (remaining > 0) @@ -64,6 +69,9 @@ namespace LibHac.FsSystem long inOffset = offset; int outOffset = 0; + if (!IsRangeValid(offset, source.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + lock (Blocks) { while (remaining > 0) @@ -87,7 +95,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { lock (Blocks) { @@ -100,13 +108,13 @@ namespace LibHac.FsSystem return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { - size = _length; + size = Length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { Result rc = BaseStorage.SetSize(size); if (rc.IsFailure()) return rc; @@ -114,11 +122,19 @@ namespace LibHac.FsSystem rc = BaseStorage.GetSize(out long newSize); if (rc.IsFailure()) return rc; - _length = newSize; + Length = newSize; return Result.Success; } + protected override void Dispose(bool disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + private CacheBlock GetBlock(long blockIndex) { if (BlockDict.TryGetValue(blockIndex, out LinkedListNode node)) @@ -157,9 +173,9 @@ namespace LibHac.FsSystem long offset = index * BlockSize; int length = BlockSize; - if (_length != -1) + if (Length != -1) { - length = (int)Math.Min(_length - offset, length); + length = (int)Math.Min(Length - offset, length); } BaseStorage.Read(offset, block.Buffer.AsSpan(0, length)).ThrowIfFailure(); diff --git a/src/LibHac/FsSystem/ConcatenationStorage.cs b/src/LibHac/FsSystem/ConcatenationStorage.cs index 9bce2554..13ef9c5e 100644 --- a/src/LibHac/FsSystem/ConcatenationStorage.cs +++ b/src/LibHac/FsSystem/ConcatenationStorage.cs @@ -7,12 +7,13 @@ namespace LibHac.FsSystem public class ConcatenationStorage : StorageBase { private ConcatSource[] Sources { get; } - private long _length; + private long Length { get; } + private bool LeaveOpen { get; } public ConcatenationStorage(IList sources, bool leaveOpen) { Sources = new ConcatSource[sources.Count]; - if (!leaveOpen) ToDispose.AddRange(sources); + LeaveOpen = leaveOpen; long length = 0; for (int i = 0; i < sources.Count; i++) @@ -24,7 +25,7 @@ namespace LibHac.FsSystem length += sourceSize; } - _length = length; + Length = length; } protected override Result ReadImpl(long offset, Span destination) @@ -32,6 +33,10 @@ namespace LibHac.FsSystem long inPos = offset; int outPos = 0; int remaining = destination.Length; + + if (!IsRangeValid(offset, destination.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + int sourceIndex = FindSource(inPos); while (remaining > 0) @@ -59,6 +64,10 @@ namespace LibHac.FsSystem long inPos = offset; int outPos = 0; int remaining = source.Length; + + if (!IsRangeValid(offset, source.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + int sourceIndex = FindSource(inPos); while (remaining > 0) @@ -81,7 +90,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { foreach (ConcatSource source in Sources) { @@ -92,15 +101,34 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result GetSize(out long size) + protected override Result SetSizeImpl(long size) { - size = _length; + return ResultFs.NotImplemented.Log(); + } + + protected override Result GetSizeImpl(out long size) + { + size = Length; return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen && Sources != null) + { + foreach (ConcatSource source in Sources) + { + source?.Storage?.Dispose(); + } + } + } + } + private int FindSource(long offset) { - if (offset < 0 || offset >= _length) + if (offset < 0 || offset >= Length) throw new ArgumentOutOfRangeException(nameof(offset), offset, "The Storage does not contain this offset."); int lo = 0; diff --git a/src/LibHac/FsSystem/FileStorage.cs b/src/LibHac/FsSystem/FileStorage.cs index a1865732..d9cc1f88 100644 --- a/src/LibHac/FsSystem/FileStorage.cs +++ b/src/LibHac/FsSystem/FileStorage.cs @@ -22,17 +22,17 @@ namespace LibHac.FsSystem return BaseFile.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { return BaseFile.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { return BaseFile.GetSize(out size); } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { return BaseFile.SetSize(size); } diff --git a/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs b/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs index 4d6d14be..520436ea 100644 --- a/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs +++ b/src/LibHac/FsSystem/HierarchicalIntegrityVerificationStorage.cs @@ -18,7 +18,8 @@ namespace LibHac.FsSystem /// public Validity[][] LevelValidities { get; } - private long _length; + private long Length { get; } + private bool LeaveOpen { get; } private IntegrityVerificationStorage[] IntegrityStorages { get; } @@ -44,9 +45,10 @@ namespace LibHac.FsSystem } DataLevel = Levels[Levels.Length - 1]; - DataLevel.GetSize(out _length).ThrowIfFailure(); + DataLevel.GetSize(out long dataSize).ThrowIfFailure(); + Length = dataSize; - if (!leaveOpen) ToDispose.Add(DataLevel); + LeaveOpen = leaveOpen; } public HierarchicalIntegrityVerificationStorage(IvfcHeader header, IStorage masterHash, IStorage data, @@ -104,17 +106,33 @@ namespace LibHac.FsSystem return DataLevel.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { return DataLevel.Flush(); } - public override Result GetSize(out long size) + protected override Result SetSizeImpl(long size) { - size = _length; + return ResultFs.UnsupportedOperationInHierarchicalIvfcStorageSetSize.Log(); + } + + protected override Result GetSizeImpl(out long size) + { + size = Length; return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + DataLevel?.Dispose(); + } + } + } + /// /// Checks the hashes of any unchecked blocks and returns the of the data. /// @@ -127,7 +145,7 @@ namespace LibHac.FsSystem IntegrityVerificationStorage storage = IntegrityStorages[IntegrityStorages.Length - 1]; long blockSize = storage.SectorSize; - int blockCount = (int)Util.DivideByRoundUp(_length, blockSize); + int blockCount = (int)Util.DivideByRoundUp(Length, blockSize); var buffer = new byte[blockSize]; var result = Validity.Valid; diff --git a/src/LibHac/FsSystem/IndirectStorage.cs b/src/LibHac/FsSystem/IndirectStorage.cs index e2c0dc05..c1387d8e 100644 --- a/src/LibHac/FsSystem/IndirectStorage.cs +++ b/src/LibHac/FsSystem/IndirectStorage.cs @@ -12,20 +12,21 @@ namespace LibHac.FsSystem private List Sources { get; } = new List(); private BucketTree BucketTree { get; } - private long _length; + private long Length { get; } + private bool LeaveOpen { get; } public IndirectStorage(IStorage bucketTreeData, bool leaveOpen, params IStorage[] sources) { Sources.AddRange(sources); - if (!leaveOpen) ToDispose.AddRange(sources); + LeaveOpen = leaveOpen; BucketTree = new BucketTree(bucketTreeData); RelocationEntries = BucketTree.GetEntryList(); RelocationOffsets = RelocationEntries.Select(x => x.Offset).ToList(); - _length = BucketTree.BucketOffsets.OffsetEnd; + Length = BucketTree.BucketOffsets.OffsetEnd; } protected override Result ReadImpl(long offset, Span destination) @@ -68,22 +69,36 @@ namespace LibHac.FsSystem return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log(); } - public override Result Flush() + protected override Result FlushImpl() { return Result.Success; } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { - size = _length; + size = Length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperationInIndirectStorageSetSize.Log(); } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen && Sources != null) + { + foreach (IStorage storage in Sources) + { + storage?.Dispose(); + } + } + } + } + private RelocationEntry GetRelocationEntry(long offset) { int index = RelocationOffsets.BinarySearch(offset); diff --git a/src/LibHac/FsSystem/IntegrityVerificationStorage.cs b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs index 49d14636..6f10630b 100644 --- a/src/LibHac/FsSystem/IntegrityVerificationStorage.cs +++ b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs @@ -124,7 +124,7 @@ namespace LibHac.FsSystem public Result Read(long offset, Span destination, IntegrityCheckLevel integrityCheckLevel) { - ValidateParameters(destination, offset); + // ValidateParameters(destination, offset); return ReadImpl(offset, destination, integrityCheckLevel); } @@ -188,12 +188,12 @@ namespace LibHac.FsSystem } } - public override Result Flush() + protected override Result FlushImpl() { Result rc = HashStorage.Flush(); if (rc.IsFailure()) return rc; - return base.Flush(); + return base.FlushImpl(); } public void FsTrim() diff --git a/src/LibHac/FsSystem/LocalStorage.cs b/src/LibHac/FsSystem/LocalStorage.cs index 7e8d6596..ebc47f58 100644 --- a/src/LibHac/FsSystem/LocalStorage.cs +++ b/src/LibHac/FsSystem/LocalStorage.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; namespace LibHac.FsSystem { @@ -16,9 +17,6 @@ namespace LibHac.FsSystem Path = path; Stream = new FileStream(Path, mode, access); Storage = new StreamStorage(Stream, false); - - ToDispose.Add(Storage); - ToDispose.Add(Stream); } protected override Result ReadImpl(long offset, Span destination) @@ -31,14 +29,28 @@ namespace LibHac.FsSystem return Storage.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { return Storage.Flush(); } - public override Result GetSize(out long size) + protected override Result SetSizeImpl(long size) + { + return ResultFs.NotImplemented.Log(); + } + + protected override Result GetSizeImpl(out long size) { return Storage.GetSize(out size); } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + Storage?.Dispose(); + Stream?.Dispose(); + } + } } } diff --git a/src/LibHac/FsSystem/MemoryStorage.cs b/src/LibHac/FsSystem/MemoryStorage.cs index 8ec783a5..b655b885 100644 --- a/src/LibHac/FsSystem/MemoryStorage.cs +++ b/src/LibHac/FsSystem/MemoryStorage.cs @@ -10,7 +10,7 @@ namespace LibHac.FsSystem private int _length; private int _capacity; private bool _isExpandable; - + public MemoryStorage() : this(0) { } public MemoryStorage(int capacity) @@ -19,7 +19,6 @@ namespace LibHac.FsSystem _capacity = capacity; _isExpandable = true; - CanAutoExpand = true; _buffer = new byte[capacity]; } @@ -41,6 +40,9 @@ namespace LibHac.FsSystem protected override Result ReadImpl(long offset, Span destination) { + if (!IsRangeValid(offset, destination.Length, _length)) + return ResultFs.ValueOutOfRange.Log(); + _buffer.AsSpan((int)(_start + offset), destination.Length).CopyTo(destination); return Result.Success; @@ -48,6 +50,9 @@ namespace LibHac.FsSystem protected override Result WriteImpl(long offset, ReadOnlySpan source) { + if (!IsRangeValid(offset, source.Length, _length)) + return ResultFs.ValueOutOfRange.Log(); + long requiredCapacity = _start + offset + source.Length; if (requiredCapacity > _length) @@ -97,15 +102,15 @@ namespace LibHac.FsSystem } } - public override Result Flush() => Result.Success; + protected override Result FlushImpl() => Result.Success; - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { size = _length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperationInMemoryStorageSetSize.Log(); } diff --git a/src/LibHac/FsSystem/NullStorage.cs b/src/LibHac/FsSystem/NullStorage.cs index ba78a51b..81b4d23e 100644 --- a/src/LibHac/FsSystem/NullStorage.cs +++ b/src/LibHac/FsSystem/NullStorage.cs @@ -8,10 +8,11 @@ namespace LibHac.FsSystem /// public class NullStorage : StorageBase { - public NullStorage() { } - public NullStorage(long length) => _length = length; + private long Length { get; } + + public NullStorage() { } + public NullStorage(long length) => Length = length; - private long _length; protected override Result ReadImpl(long offset, Span destination) { @@ -24,14 +25,19 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { return Result.Success; } - public override Result GetSize(out long size) + protected override Result SetSizeImpl(long size) { - size = _length; + return ResultFs.NotImplemented.Log(); + } + + protected override Result GetSizeImpl(out long size) + { + size = Length; return Result.Success; } } diff --git a/src/LibHac/FsSystem/Save/AllocationTableStorage.cs b/src/LibHac/FsSystem/Save/AllocationTableStorage.cs index 1e8b60c0..f68dfe16 100644 --- a/src/LibHac/FsSystem/Save/AllocationTableStorage.cs +++ b/src/LibHac/FsSystem/Save/AllocationTableStorage.cs @@ -83,18 +83,18 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { size = _length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { int oldBlockCount = (int)Util.DivideByRoundUp(_length, BlockSize); int newBlockCount = (int)Util.DivideByRoundUp(size, BlockSize); diff --git a/src/LibHac/FsSystem/Save/DuplexStorage.cs b/src/LibHac/FsSystem/Save/DuplexStorage.cs index 6ac63544..e36fa7cb 100644 --- a/src/LibHac/FsSystem/Save/DuplexStorage.cs +++ b/src/LibHac/FsSystem/Save/DuplexStorage.cs @@ -11,7 +11,7 @@ namespace LibHac.FsSystem.Save private IStorage DataB { get; } private DuplexBitmap Bitmap { get; } - private long _length; + private long Length { get; } public DuplexStorage(IStorage dataA, IStorage dataB, IStorage bitmap, int blockSize) { @@ -23,7 +23,8 @@ namespace LibHac.FsSystem.Save bitmap.GetSize(out long bitmapSize).ThrowIfFailure(); Bitmap = new DuplexBitmap(BitmapStorage, (int)(bitmapSize * 8)); - DataA.GetSize(out _length).ThrowIfFailure(); + DataA.GetSize(out long dataSize).ThrowIfFailure(); + Length = dataSize; } protected override Result ReadImpl(long offset, Span destination) @@ -32,6 +33,9 @@ namespace LibHac.FsSystem.Save int outPos = 0; int remaining = destination.Length; + if (!IsRangeValid(offset, destination.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + while (remaining > 0) { int blockNum = (int)(inPos / BlockSize); @@ -58,6 +62,9 @@ namespace LibHac.FsSystem.Save int outPos = 0; int remaining = source.Length; + if (!IsRangeValid(offset, source.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + while (remaining > 0) { int blockNum = (int)(inPos / BlockSize); @@ -78,7 +85,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { Result rc = BitmapStorage.Flush(); if (rc.IsFailure()) return rc; @@ -92,9 +99,14 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result GetSize(out long size) + protected override Result SetSizeImpl(long size) { - size = _length; + return ResultFs.NotImplemented.Log(); + } + + protected override Result GetSizeImpl(out long size) + { + size = Length; return Result.Success; } diff --git a/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs b/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs index e942fbd6..132b3ad5 100644 --- a/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs +++ b/src/LibHac/FsSystem/Save/HierarchicalDuplexStorage.cs @@ -7,7 +7,7 @@ namespace LibHac.FsSystem.Save { private DuplexStorage[] Layers { get; } private DuplexStorage DataLayer { get; } - private long _length; + private long Length { get; } public HierarchicalDuplexStorage(DuplexFsLayerInfo[] layers, bool masterBit) { @@ -30,7 +30,8 @@ namespace LibHac.FsSystem.Save } DataLayer = Layers[Layers.Length - 1]; - DataLayer.GetSize(out _length).ThrowIfFailure(); + DataLayer.GetSize(out long dataSize).ThrowIfFailure(); + Length = dataSize; } protected override Result ReadImpl(long offset, Span destination) @@ -43,14 +44,19 @@ namespace LibHac.FsSystem.Save return DataLayer.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { return DataLayer.Flush(); } - public override Result GetSize(out long size) + protected override Result SetSizeImpl(long size) { - size = _length; + return ResultFs.NotImplemented.Log(); + } + + protected override Result GetSizeImpl(out long size) + { + size = Length; return Result.Success; } diff --git a/src/LibHac/FsSystem/Save/JournalStorage.cs b/src/LibHac/FsSystem/Save/JournalStorage.cs index 5897b145..1ac69416 100644 --- a/src/LibHac/FsSystem/Save/JournalStorage.cs +++ b/src/LibHac/FsSystem/Save/JournalStorage.cs @@ -15,7 +15,8 @@ namespace LibHac.FsSystem.Save public int BlockSize { get; } - private long _length; + private long Length { get; } + private bool LeaveOpen { get; } public JournalStorage(IStorage baseStorage, IStorage header, JournalMapParams mapInfo, bool leaveOpen) { @@ -27,9 +28,9 @@ namespace LibHac.FsSystem.Save Map = new JournalMap(mapHeader, mapInfo); BlockSize = (int)Header.BlockSize; - _length = Header.TotalSize - Header.JournalSize; + Length = Header.TotalSize - Header.JournalSize; - if (!leaveOpen) ToDispose.Add(baseStorage); + LeaveOpen = leaveOpen; } protected override Result ReadImpl(long offset, Span destination) @@ -38,6 +39,9 @@ namespace LibHac.FsSystem.Save int outPos = 0; int remaining = destination.Length; + if (!IsRangeValid(offset, destination.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + while (remaining > 0) { int blockNum = (int)(inPos / BlockSize); @@ -64,6 +68,9 @@ namespace LibHac.FsSystem.Save int outPos = 0; int remaining = source.Length; + if (!IsRangeValid(offset, source.Length, Length)) + return ResultFs.ValueOutOfRange.Log(); + while (remaining > 0) { int blockNum = (int)(inPos / BlockSize); @@ -84,17 +91,33 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result SetSizeImpl(long size) { - size = _length; + return ResultFs.NotImplemented.Log(); + } + + protected override Result GetSizeImpl(out long size) + { + size = Length; return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + } + public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); diff --git a/src/LibHac/FsSystem/Save/RemapStorage.cs b/src/LibHac/FsSystem/Save/RemapStorage.cs index a392a63d..32432176 100644 --- a/src/LibHac/FsSystem/Save/RemapStorage.cs +++ b/src/LibHac/FsSystem/Save/RemapStorage.cs @@ -13,6 +13,7 @@ namespace LibHac.FsSystem.Save private IStorage BaseStorage { get; } private IStorage HeaderStorage { get; } private IStorage MapEntryStorage { get; } + private bool LeaveOpen { get; } private RemapHeader Header { get; } public MapEntry[] MapEntries { get; set; } @@ -42,7 +43,7 @@ namespace LibHac.FsSystem.Save MapEntries[i] = new MapEntry(reader); } - if (!leaveOpen) ToDispose.Add(BaseStorage); + LeaveOpen = leaveOpen; Segments = InitSegments(Header, MapEntries); } @@ -109,18 +110,34 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result SetSizeImpl(long size) + { + return ResultFs.UnsupportedOperationInHierarchicalIvfcStorageSetSize.Log(); + } + + protected override Result GetSizeImpl(out long size) { // todo: Different result code size = -1; return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + } + public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); public IStorage GetMapEntryStorage() => MapEntryStorage.AsReadOnly(); diff --git a/src/LibHac/FsSystem/SectorStorage.cs b/src/LibHac/FsSystem/SectorStorage.cs index 1760ad3f..6e0a09bc 100644 --- a/src/LibHac/FsSystem/SectorStorage.cs +++ b/src/LibHac/FsSystem/SectorStorage.cs @@ -10,7 +10,8 @@ namespace LibHac.FsSystem public int SectorSize { get; } public int SectorCount { get; private set; } - private long _length; + private long Length { get; set; } + private bool LeaveOpen { get; } public SectorStorage(IStorage baseStorage, int sectorSize, bool leaveOpen) { @@ -20,9 +21,9 @@ namespace LibHac.FsSystem baseStorage.GetSize(out long baseSize).ThrowIfFailure(); SectorCount = (int)Util.DivideByRoundUp(baseSize, SectorSize); - _length = baseSize; + Length = baseSize; - if (!leaveOpen) ToDispose.Add(BaseStorage); + LeaveOpen = leaveOpen; } protected override Result ReadImpl(long offset, Span destination) @@ -37,18 +38,18 @@ namespace LibHac.FsSystem return BaseStorage.Write(offset, source); } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { - size = _length; + size = Length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { Result rc = BaseStorage.SetSize(size); if (rc.IsFailure()) return rc; @@ -57,11 +58,22 @@ namespace LibHac.FsSystem if (rc.IsFailure()) return rc; SectorCount = (int)Util.DivideByRoundUp(newSize, SectorSize); - _length = newSize; + Length = newSize; return Result.Success; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + } + /// /// Validates that the size is a multiple of the sector size /// diff --git a/src/LibHac/FsSystem/StorageBase.cs b/src/LibHac/FsSystem/StorageBase.cs deleted file mode 100644 index 267bb83c..00000000 --- a/src/LibHac/FsSystem/StorageBase.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using LibHac.Fs; - -namespace LibHac.FsSystem -{ - public abstract class StorageBase : IStorage - { - private bool _isDisposed; - protected internal List ToDispose { get; } = new List(); - protected bool CanAutoExpand { get; set; } - - protected abstract Result ReadImpl(long offset, Span destination); - protected abstract Result WriteImpl(long offset, ReadOnlySpan source); - public abstract Result Flush(); - public abstract Result GetSize(out long size); - - public Result Read(long offset, Span destination) - { - ValidateParameters(destination, offset); - return ReadImpl(offset, destination); - } - - public Result Write(long offset, ReadOnlySpan source) - { - ValidateParameters(source, offset); - return WriteImpl(offset, source); - } - - public virtual Result SetSize(long size) - { - return ResultFs.NotImplemented.Log(); - } - - protected virtual void Dispose(bool disposing) - { - if (_isDisposed) return; - - if (disposing) - { - Flush(); - foreach (IDisposable item in ToDispose) - { - item?.Dispose(); - } - } - - _isDisposed = true; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected void ValidateParameters(ReadOnlySpan span, long offset) - { - if (_isDisposed) throw new ObjectDisposedException(null); - if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative."); - - Result sizeResult = GetSize(out long length); - sizeResult.ThrowIfFailure(); - - if (length != -1 && !CanAutoExpand) - { - if (offset + span.Length > length) throw new ArgumentException("The given offset and count exceed the length of the Storage"); - } - } - } -} diff --git a/src/LibHac/FsSystem/StreamStorage.cs b/src/LibHac/FsSystem/StreamStorage.cs index 7381f63a..85505e87 100644 --- a/src/LibHac/FsSystem/StreamStorage.cs +++ b/src/LibHac/FsSystem/StreamStorage.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Fs; #if !STREAM_SPAN using System.Buffers; @@ -13,13 +14,14 @@ namespace LibHac.FsSystem private Stream BaseStream { get; } private object Locker { get; } = new object(); - private long _length; + private long Length { get; } + private bool LeaveOpen { get; } public StreamStorage(Stream baseStream, bool leaveOpen) { BaseStream = baseStream; - _length = BaseStream.Length; - if (!leaveOpen) ToDispose.Add(BaseStream); + Length = BaseStream.Length; + LeaveOpen = leaveOpen; } protected override Result ReadImpl(long offset, Span destination) @@ -90,7 +92,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result Flush() + protected override Result FlushImpl() { lock (Locker) { @@ -100,10 +102,26 @@ namespace LibHac.FsSystem } } - public override Result GetSize(out long size) + protected override Result SetSizeImpl(long size) { - size = _length; + return ResultFs.NotImplemented.Log(); + } + + protected override Result GetSizeImpl(out long size) + { + size = Length; return Result.Success; } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStream?.Dispose(); + } + } + } } } diff --git a/src/LibHac/FsSystem/SubStorage.cs b/src/LibHac/FsSystem/SubStorage.cs index 24d4c67d..efaa4b7e 100644 --- a/src/LibHac/FsSystem/SubStorage.cs +++ b/src/LibHac/FsSystem/SubStorage.cs @@ -9,26 +9,27 @@ namespace LibHac.FsSystem private IStorage BaseStorage { get; } private long Offset { get; } private FileAccess Access { get; } = FileAccess.ReadWrite; - private long _length; + private long Length { get; set; } + private bool LeaveOpen { get; } public SubStorage(IStorage baseStorage, long offset, long length) { BaseStorage = baseStorage; Offset = offset; - _length = length; + Length = length; } public SubStorage(SubStorage baseStorage, long offset, long length) { BaseStorage = baseStorage.BaseStorage; Offset = baseStorage.Offset + offset; - _length = length; + Length = length; } public SubStorage(IStorage baseStorage, long offset, long length, bool leaveOpen) : this(baseStorage, offset, length) { - if (!leaveOpen) ToDispose.Add(BaseStorage); + LeaveOpen = leaveOpen; } public SubStorage(IStorage baseStorage, long offset, long length, bool leaveOpen, FileAccess access) @@ -49,18 +50,18 @@ namespace LibHac.FsSystem return BaseStorage.Write(offset + Offset, source); } - public override Result Flush() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { - size = _length; + size = Length; return Result.Success; } - public override Result SetSize(long size) + protected override Result SetSizeImpl(long size) { if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log(); @@ -72,7 +73,7 @@ namespace LibHac.FsSystem Result rc = BaseStorage.GetSize(out long baseSize); if (rc.IsFailure()) return rc; - if (baseSize != Offset + _length) + if (baseSize != Offset + Length) { // SubStorage cannot be resized unless it is located at the end of the base storage. return ResultFs.SubStorageNotResizableMiddleOfFile.Log(); @@ -81,9 +82,20 @@ namespace LibHac.FsSystem rc = BaseStorage.SetSize(Offset + size); if (rc.IsFailure()) return rc; - _length = size; + Length = size; return Result.Success; } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (!LeaveOpen) + { + BaseStorage?.Dispose(); + } + } + } } } From 8f4c310b7e5e063b70e56459fd9f508bda6fecc0 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 11 Oct 2019 19:11:36 -0500 Subject: [PATCH 44/46] Add FileSystemBase --- src/LibHac/Fs/FileBase.cs | 7 +- src/LibHac/Fs/FileSystemBase.cs | 196 ++++++++++++++++++ src/LibHac/FsSystem/AesXtsFileSystem.cs | 34 +-- .../FsSystem/ConcatenationFileSystem.cs | 34 +-- .../FsSystem/DirectorySaveDataFileSystem.cs | 52 ++--- src/LibHac/FsSystem/LayeredFileSystem.cs | 42 ++-- src/LibHac/FsSystem/PartitionFileSystem.cs | 46 ++-- src/LibHac/FsSystem/ReadOnlyFileSystem.cs | 40 ++-- src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs | 44 ++-- .../FsSystem/Save/SaveDataFileSystem.cs | 42 ++-- .../FsSystem/Save/SaveDataFileSystemCore.cs | 44 ++-- src/LibHac/FsSystem/SubdirectoryFileSystem.cs | 34 +-- 12 files changed, 359 insertions(+), 256 deletions(-) create mode 100644 src/LibHac/Fs/FileSystemBase.cs diff --git a/src/LibHac/Fs/FileBase.cs b/src/LibHac/Fs/FileBase.cs index 887dfa98..6aec6529 100644 --- a/src/LibHac/Fs/FileBase.cs +++ b/src/LibHac/Fs/FileBase.cs @@ -55,8 +55,11 @@ namespace LibHac.Fs public Result GetSize(out long size) { - size = default; - if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + if (IsDisposed) + { + size = default; + return ResultFs.PreconditionViolation.Log(); + } return GetSizeImpl(out size); } diff --git a/src/LibHac/Fs/FileSystemBase.cs b/src/LibHac/Fs/FileSystemBase.cs new file mode 100644 index 00000000..3f6ec78f --- /dev/null +++ b/src/LibHac/Fs/FileSystemBase.cs @@ -0,0 +1,196 @@ +using System; +using System.Threading; + +namespace LibHac.Fs +{ + public abstract class FileSystemBase : IFileSystem + { + // 0 = not disposed; 1 = disposed + private int _disposedState; + private bool IsDisposed => _disposedState != 0; + + protected abstract Result CreateDirectoryImpl(string path); + protected abstract Result CreateFileImpl(string path, long size, CreateFileOptions options); + protected abstract Result DeleteDirectoryImpl(string path); + protected abstract Result DeleteDirectoryRecursivelyImpl(string path); + protected abstract Result CleanDirectoryRecursivelyImpl(string path); + protected abstract Result DeleteFileImpl(string path); + protected abstract Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode); + protected abstract Result OpenFileImpl(out IFile file, string path, OpenMode mode); + protected abstract Result RenameDirectoryImpl(string oldPath, string newPath); + protected abstract Result RenameFileImpl(string oldPath, string newPath); + protected abstract Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path); + protected abstract Result CommitImpl(); + + public Result CreateDirectory(string path) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return CreateDirectoryImpl(path); + } + + public Result CreateFile(string path, long size, CreateFileOptions options) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return CreateFileImpl(path, size, options); + } + + public Result DeleteDirectory(string path) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return DeleteDirectoryImpl(path); + } + + public Result DeleteDirectoryRecursively(string path) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return DeleteDirectoryRecursivelyImpl(path); + } + + public Result CleanDirectoryRecursively(string path) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return CleanDirectoryRecursivelyImpl(path); + } + + public Result DeleteFile(string path) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return DeleteFileImpl(path); + } + + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + { + if (IsDisposed) + { + directory = default; + return ResultFs.PreconditionViolation.Log(); + } + + return OpenDirectoryImpl(out directory, path, mode); + } + + public Result OpenFile(out IFile file, string path, OpenMode mode) + { + if (IsDisposed) + { + file = default; + return ResultFs.PreconditionViolation.Log(); + } + + return OpenFileImpl(out file, path, mode); + } + + public Result RenameDirectory(string oldPath, string newPath) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return RenameDirectoryImpl(oldPath, newPath); + } + + public Result RenameFile(string oldPath, string newPath) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return RenameFileImpl(oldPath, newPath); + } + + public Result GetEntryType(out DirectoryEntryType entryType, string path) + { + if (IsDisposed) + { + entryType = default; + return ResultFs.PreconditionViolation.Log(); + } + + return GetEntryTypeImpl(out entryType, path); + } + + public Result GetFreeSpaceSize(out long freeSpace, string path) + { + if (IsDisposed) + { + freeSpace = default; + return ResultFs.PreconditionViolation.Log(); + } + + return GetFreeSpaceSizeImpl(out freeSpace, path); + } + + public Result GetTotalSpaceSize(out long totalSpace, string path) + { + if (IsDisposed) + { + totalSpace = default; + return ResultFs.PreconditionViolation.Log(); + } + + return GetTotalSpaceSizeImpl(out totalSpace, path); + } + + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) + { + if (IsDisposed) + { + timeStamp = default; + return ResultFs.PreconditionViolation.Log(); + } + + return GetFileTimeStampRawImpl(out timeStamp, path); + } + + public Result Commit() + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return CommitImpl(); + } + + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return QueryEntryImpl(outBuffer, inBuffer, queryId, path); + } + + public void Dispose() + { + // Make sure Dispose is only called once + if (Interlocked.CompareExchange(ref _disposedState, 1, 0) == 0) + { + Dispose(true); + GC.SuppressFinalize(this); + } + } + + protected virtual void Dispose(bool disposing) { } + + protected virtual Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + { + freeSpace = default; + return ResultFs.NotImplemented.Log(); + } + + protected virtual Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + { + totalSpace = default; + return ResultFs.NotImplemented.Log(); + } + + protected virtual Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) + { + timeStamp = default; + return ResultFs.NotImplemented.Log(); + } + + protected virtual Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + { + return ResultFs.NotImplemented.Log(); + } + } +} diff --git a/src/LibHac/FsSystem/AesXtsFileSystem.cs b/src/LibHac/FsSystem/AesXtsFileSystem.cs index 118200bb..45c04399 100644 --- a/src/LibHac/FsSystem/AesXtsFileSystem.cs +++ b/src/LibHac/FsSystem/AesXtsFileSystem.cs @@ -4,7 +4,7 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class AesXtsFileSystem : IFileSystem + public class AesXtsFileSystem : FileSystemBase { public int BlockSize { get; } @@ -28,12 +28,12 @@ namespace LibHac.FsSystem BlockSize = blockSize; } - public Result CreateDirectory(string path) + protected override Result CreateDirectoryImpl(string path) { return BaseFileSystem.CreateDirectory(path); } - public Result CreateFile(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) { return CreateFile(path, size, options, new byte[0x20]); } @@ -67,27 +67,27 @@ namespace LibHac.FsSystem return Result.Success; } - public Result DeleteDirectory(string path) + protected override Result DeleteDirectoryImpl(string path) { return BaseFileSystem.DeleteDirectory(path); } - public Result DeleteDirectoryRecursively(string path) + protected override Result DeleteDirectoryRecursivelyImpl(string path) { return BaseFileSystem.DeleteDirectoryRecursively(path); } - public Result CleanDirectoryRecursively(string path) + protected override Result CleanDirectoryRecursivelyImpl(string path) { return BaseFileSystem.CleanDirectoryRecursively(path); } - public Result DeleteFile(string path) + protected override Result DeleteFileImpl(string path) { return BaseFileSystem.DeleteFile(path); } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { directory = default; path = PathTools.Normalize(path); @@ -99,7 +99,7 @@ namespace LibHac.FsSystem return Result.Success; } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { file = default; path = PathTools.Normalize(path); @@ -113,7 +113,7 @@ namespace LibHac.FsSystem return Result.Success; } - public Result RenameDirectory(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(string oldPath, string newPath) { oldPath = PathTools.Normalize(oldPath); newPath = PathTools.Normalize(newPath); @@ -176,7 +176,7 @@ namespace LibHac.FsSystem } } - public Result RenameFile(string oldPath, string newPath) + protected override Result RenameFileImpl(string oldPath, string newPath) { oldPath = PathTools.Normalize(oldPath); newPath = PathTools.Normalize(newPath); @@ -202,32 +202,32 @@ namespace LibHac.FsSystem return Result.Success; } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { return BaseFileSystem.GetEntryType(out entryType, path); } - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) { return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path); } - public Result GetFreeSpaceSize(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) { return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path); } - public Result GetTotalSpaceSize(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) { return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path); } - public Result Commit() + protected override Result CommitImpl() { return BaseFileSystem.Commit(); } - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, path); } diff --git a/src/LibHac/FsSystem/ConcatenationFileSystem.cs b/src/LibHac/FsSystem/ConcatenationFileSystem.cs index 5c60d594..f90045ac 100644 --- a/src/LibHac/FsSystem/ConcatenationFileSystem.cs +++ b/src/LibHac/FsSystem/ConcatenationFileSystem.cs @@ -21,7 +21,7 @@ namespace LibHac.FsSystem /// Each sub-file except the final one must have the size that was specified /// at the creation of the . /// - public class ConcatenationFileSystem : IFileSystem + public class ConcatenationFileSystem : FileSystemBase { private const long DefaultSubFileSize = 0xFFFF0000; // Hard-coded value used by FS private IAttributeFileSystem BaseFileSystem { get; } @@ -104,7 +104,7 @@ namespace LibHac.FsSystem return BaseFileSystem.SetFileAttributes(path, NxFileAttributes.Archive); } - public Result CreateDirectory(string path) + protected override Result CreateDirectoryImpl(string path) { path = PathTools.Normalize(path); string parent = PathTools.GetParentDirectory(path); @@ -118,7 +118,7 @@ namespace LibHac.FsSystem return BaseFileSystem.CreateDirectory(path); } - public Result CreateFile(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); @@ -162,7 +162,7 @@ namespace LibHac.FsSystem return Result.Success; } - public Result DeleteDirectory(string path) + protected override Result DeleteDirectoryImpl(string path) { path = PathTools.Normalize(path); @@ -174,7 +174,7 @@ namespace LibHac.FsSystem return BaseFileSystem.DeleteDirectory(path); } - public Result DeleteDirectoryRecursively(string path) + protected override Result DeleteDirectoryRecursivelyImpl(string path) { path = PathTools.Normalize(path); @@ -183,7 +183,7 @@ namespace LibHac.FsSystem return BaseFileSystem.DeleteDirectoryRecursively(path); } - public Result CleanDirectoryRecursively(string path) + protected override Result CleanDirectoryRecursivelyImpl(string path) { path = PathTools.Normalize(path); @@ -192,7 +192,7 @@ namespace LibHac.FsSystem return BaseFileSystem.CleanDirectoryRecursively(path); } - public Result DeleteFile(string path) + protected override Result DeleteFileImpl(string path) { path = PathTools.Normalize(path); @@ -212,7 +212,7 @@ namespace LibHac.FsSystem return BaseFileSystem.DeleteDirectory(path); } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { directory = default; path = PathTools.Normalize(path); @@ -229,7 +229,7 @@ namespace LibHac.FsSystem return Result.Success; } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { file = default; path = PathTools.Normalize(path); @@ -257,7 +257,7 @@ namespace LibHac.FsSystem return Result.Success; } - public Result RenameDirectory(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(string oldPath, string newPath) { oldPath = PathTools.Normalize(oldPath); newPath = PathTools.Normalize(newPath); @@ -270,7 +270,7 @@ namespace LibHac.FsSystem return BaseFileSystem.RenameDirectory(oldPath, newPath); } - public Result RenameFile(string oldPath, string newPath) + protected override Result RenameFileImpl(string oldPath, string newPath) { oldPath = PathTools.Normalize(oldPath); newPath = PathTools.Normalize(newPath); @@ -285,7 +285,7 @@ namespace LibHac.FsSystem } } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); @@ -298,27 +298,27 @@ namespace LibHac.FsSystem return BaseFileSystem.GetEntryType(out entryType, path); } - public Result GetFreeSpaceSize(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) { return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path); } - public Result GetTotalSpaceSize(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) { return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path); } - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) { return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path); } - public Result Commit() + protected override Result CommitImpl() { return BaseFileSystem.Commit(); } - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { if (queryId != QueryId.MakeConcatFile) return ResultFs.UnsupportedOperationInConcatFsQueryEntry.Log(); diff --git a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs index 4a5838fa..93e03091 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs @@ -1,9 +1,8 @@ -using System; -using LibHac.Fs; +using LibHac.Fs; namespace LibHac.FsSystem { - public class DirectorySaveDataFileSystem : IFileSystem + public class DirectorySaveDataFileSystem : FileSystemBase { private const string CommittedDir = "/0/"; private const string WorkingDir = "/1/"; @@ -34,7 +33,7 @@ namespace LibHac.FsSystem } } - public Result CreateDirectory(string path) + protected override Result CreateDirectoryImpl(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); @@ -44,7 +43,7 @@ namespace LibHac.FsSystem } } - public Result CreateFile(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) { string fullPath = GetFullPath(PathTools.Normalize(path)); @@ -54,7 +53,7 @@ namespace LibHac.FsSystem } } - public Result DeleteDirectory(string path) + protected override Result DeleteDirectoryImpl(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); @@ -64,7 +63,7 @@ namespace LibHac.FsSystem } } - public Result DeleteDirectoryRecursively(string path) + protected override Result DeleteDirectoryRecursivelyImpl(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); @@ -74,7 +73,7 @@ namespace LibHac.FsSystem } } - public Result CleanDirectoryRecursively(string path) + protected override Result CleanDirectoryRecursivelyImpl(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); @@ -84,7 +83,7 @@ namespace LibHac.FsSystem } } - public Result DeleteFile(string path) + protected override Result DeleteFileImpl(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); @@ -94,7 +93,7 @@ namespace LibHac.FsSystem } } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { string fullPath = GetFullPath(PathTools.Normalize(path)); @@ -104,7 +103,7 @@ namespace LibHac.FsSystem } } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { file = default; string fullPath = GetFullPath(PathTools.Normalize(path)); @@ -125,7 +124,7 @@ namespace LibHac.FsSystem } } - public Result RenameDirectory(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(string oldPath, string newPath) { string fullOldPath = GetFullPath(PathTools.Normalize(oldPath)); string fullNewPath = GetFullPath(PathTools.Normalize(newPath)); @@ -136,7 +135,7 @@ namespace LibHac.FsSystem } } - public Result RenameFile(string oldPath, string newPath) + protected override Result RenameFileImpl(string oldPath, string newPath) { string fullOldPath = GetFullPath(PathTools.Normalize(oldPath)); string fullNewPath = GetFullPath(PathTools.Normalize(newPath)); @@ -147,7 +146,7 @@ namespace LibHac.FsSystem } } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); @@ -157,25 +156,7 @@ namespace LibHac.FsSystem } } - public Result GetFreeSpaceSize(out long freeSpace, string path) - { - freeSpace = default; - return ResultFs.NotImplemented.Log(); - } - - public Result GetTotalSpaceSize(out long totalSpace, string path) - { - totalSpace = default; - return ResultFs.NotImplemented.Log(); - } - - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) - { - timeStamp = default; - return ResultFs.NotImplemented.Log(); - } - - public Result Commit() + protected override Result CommitImpl() { lock (Locker) { @@ -195,11 +176,6 @@ namespace LibHac.FsSystem } } - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) - { - return ResultFs.NotImplemented.Log(); - } - private string GetFullPath(string path) { return PathTools.Normalize(PathTools.Combine(WorkingDir, path)); diff --git a/src/LibHac/FsSystem/LayeredFileSystem.cs b/src/LibHac/FsSystem/LayeredFileSystem.cs index fe29a3fb..c48a33cb 100644 --- a/src/LibHac/FsSystem/LayeredFileSystem.cs +++ b/src/LibHac/FsSystem/LayeredFileSystem.cs @@ -4,7 +4,7 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class LayeredFileSystem : IFileSystem + public class LayeredFileSystem : FileSystemBase { private List Sources { get; } = new List(); @@ -13,7 +13,7 @@ namespace LibHac.FsSystem Sources.AddRange(sourceFileSystems); } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { directory = default; path = PathTools.Normalize(path); @@ -43,7 +43,7 @@ namespace LibHac.FsSystem return Result.Success; } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { file = default; path = PathTools.Normalize(path); @@ -67,7 +67,7 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); @@ -86,7 +86,7 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) { path = PathTools.Normalize(path); @@ -104,7 +104,7 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { path = PathTools.Normalize(path); @@ -121,30 +121,18 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - public Result Commit() + protected override Result CommitImpl() { return Result.Success; } - public Result CreateDirectory(string path) => ResultFs.UnsupportedOperation.Log(); - public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperation.Log(); - public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperation.Log(); - public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperation.Log(); - public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperation.Log(); - public Result DeleteFile(string path) => ResultFs.UnsupportedOperation.Log(); - public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); - public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); - - public Result GetFreeSpaceSize(out long freeSpace, string path) - { - freeSpace = default; - return ResultFs.UnsupportedOperation.Log(); - } - - public Result GetTotalSpaceSize(out long totalSpace, string path) - { - totalSpace = default; - return ResultFs.UnsupportedOperation.Log(); - } + protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperation.Log(); + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperation.Log(); + protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperation.Log(); + protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperation.Log(); + protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperation.Log(); + protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperation.Log(); + protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); + protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); } } diff --git a/src/LibHac/FsSystem/PartitionFileSystem.cs b/src/LibHac/FsSystem/PartitionFileSystem.cs index ece8b637..a3b8e8d1 100644 --- a/src/LibHac/FsSystem/PartitionFileSystem.cs +++ b/src/LibHac/FsSystem/PartitionFileSystem.cs @@ -7,7 +7,7 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class PartitionFileSystem : IFileSystem + public class PartitionFileSystem : FileSystemBase { // todo Re-add way of checking a file hash public PartitionFileSystemHeader Header { get; } @@ -30,13 +30,13 @@ namespace LibHac.FsSystem BaseStorage = storage; } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { directory = new PartitionDirectory(this, path, mode); return Result.Success; } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { path = PathTools.Normalize(path).TrimStart('/'); @@ -54,7 +54,7 @@ namespace LibHac.FsSystem return new PartitionFile(BaseStorage, HeaderSize + entry.Offset, entry.Size, mode); } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { entryType = DirectoryEntryType.NotFound; path = PathTools.Normalize(path); @@ -74,39 +74,19 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - public Result CreateDirectory(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public Result DeleteFile(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public Result GetFreeSpaceSize(out long freeSpace, string path) - { - freeSpace = default; - return ResultFs.NotImplemented.Log(); - } - - public Result GetTotalSpaceSize(out long totalSpace, string path) - { - totalSpace = default; - return ResultFs.NotImplemented.Log(); - } - - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) - { - timeStamp = default; - return ResultFs.NotImplemented.Log(); - } - - public Result Commit() + protected override Result CommitImpl() { return Result.Success; } - - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) => ResultFs.NotImplemented.Log(); } public enum PartitionFileSystemType diff --git a/src/LibHac/FsSystem/ReadOnlyFileSystem.cs b/src/LibHac/FsSystem/ReadOnlyFileSystem.cs index 66fc9e18..a3c4860c 100644 --- a/src/LibHac/FsSystem/ReadOnlyFileSystem.cs +++ b/src/LibHac/FsSystem/ReadOnlyFileSystem.cs @@ -1,9 +1,8 @@ -using System; -using LibHac.Fs; +using LibHac.Fs; namespace LibHac.FsSystem { - public class ReadOnlyFileSystem : IFileSystem + public class ReadOnlyFileSystem : FileSystemBase { private IFileSystem BaseFs { get; } @@ -12,12 +11,12 @@ namespace LibHac.FsSystem BaseFs = baseFileSystem; } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { return BaseFs.OpenDirectory(out directory, path, mode); } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { file = default; @@ -28,12 +27,12 @@ namespace LibHac.FsSystem return Result.Success; } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { return BaseFs.GetEntryType(out entryType, path); } - public Result GetFreeSpaceSize(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) { freeSpace = 0; return Result.Success; @@ -42,7 +41,7 @@ namespace LibHac.FsSystem // return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log(); } - public Result GetTotalSpaceSize(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) { return BaseFs.GetTotalSpaceSize(out totalSpace, path); @@ -50,7 +49,7 @@ namespace LibHac.FsSystem // return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log(); } - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) { return BaseFs.GetFileTimeStampRaw(out timeStamp, path); @@ -58,30 +57,25 @@ namespace LibHac.FsSystem // return ResultFs.NotImplemented.Log(); } - public Result Commit() + protected override Result CommitImpl() { return Result.Success; } - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) - { - return ResultFs.NotImplemented.Log(); - } + protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public Result CreateDirectory(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public Result DeleteFile(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - - public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); } } diff --git a/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs b/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs index cdd8507d..56dafb95 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs @@ -1,9 +1,8 @@ -using System; -using LibHac.Fs; +using LibHac.Fs; namespace LibHac.FsSystem.RomFs { - public class RomFsFileSystem : IFileSystem + public class RomFsFileSystem : FileSystemBase { public RomfsHeader Header { get; } @@ -23,7 +22,7 @@ namespace LibHac.FsSystem.RomFs FileTable = new HierarchicalRomFileTable(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable); } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { entryType = DirectoryEntryType.NotFound; path = PathTools.Normalize(path); @@ -43,12 +42,12 @@ namespace LibHac.FsSystem.RomFs return ResultFs.PathNotFound.Log(); } - public Result Commit() + protected override Result CommitImpl() { return Result.Success; } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { directory = default; path = PathTools.Normalize(path); @@ -62,7 +61,7 @@ namespace LibHac.FsSystem.RomFs return Result.Success; } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { file = default; path = PathTools.Normalize(path); @@ -87,37 +86,26 @@ namespace LibHac.FsSystem.RomFs return BaseStorage; } - public Result CreateDirectory(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public Result DeleteFile(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public Result GetFreeSpaceSize(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) { freeSpace = default; return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log(); } - public Result GetTotalSpaceSize(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) { totalSpace = default; return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log(); } - - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) - { - timeStamp = default; - return ResultFs.NotImplemented.Log(); - } - - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) - { - return ResultFs.NotImplemented.Log(); - } } public class RomfsHeader diff --git a/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs index 1e62ed3b..e0a01582 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs @@ -1,11 +1,10 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using LibHac.Fs; namespace LibHac.FsSystem.Save { - public class SaveDataFileSystem : IFileSystem + public class SaveDataFileSystem : FileSystemBase { internal const byte TrimFillValue = 0; @@ -143,113 +142,104 @@ namespace LibHac.FsSystem.Save IntegrityStorageType.Save, integrityCheckLevel, LeaveOpen); } - public Result CreateDirectory(string path) + protected override Result CreateDirectoryImpl(string path) { Result result = SaveDataFileSystemCore.CreateDirectory(path); return SaveResults.ConvertToExternalResult(result); } - public Result CreateFile(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) { Result result = SaveDataFileSystemCore.CreateFile(path, size, options); return SaveResults.ConvertToExternalResult(result); } - public Result DeleteDirectory(string path) + protected override Result DeleteDirectoryImpl(string path) { Result result = SaveDataFileSystemCore.DeleteDirectory(path); return SaveResults.ConvertToExternalResult(result); } - public Result DeleteDirectoryRecursively(string path) + protected override Result DeleteDirectoryRecursivelyImpl(string path) { Result result = SaveDataFileSystemCore.DeleteDirectoryRecursively(path); return SaveResults.ConvertToExternalResult(result); } - public Result CleanDirectoryRecursively(string path) + protected override Result CleanDirectoryRecursivelyImpl(string path) { Result result = SaveDataFileSystemCore.CleanDirectoryRecursively(path); return SaveResults.ConvertToExternalResult(result); } - public Result DeleteFile(string path) + protected override Result DeleteFileImpl(string path) { Result result = SaveDataFileSystemCore.DeleteFile(path); return SaveResults.ConvertToExternalResult(result); } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { Result result = SaveDataFileSystemCore.OpenDirectory(out directory, path, mode); return SaveResults.ConvertToExternalResult(result); } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { Result result = SaveDataFileSystemCore.OpenFile(out file, path, mode); return SaveResults.ConvertToExternalResult(result); } - public Result RenameDirectory(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(string oldPath, string newPath) { Result result = SaveDataFileSystemCore.RenameDirectory(oldPath, newPath); return SaveResults.ConvertToExternalResult(result); } - public Result RenameFile(string oldPath, string newPath) + protected override Result RenameFileImpl(string oldPath, string newPath) { Result result = SaveDataFileSystemCore.RenameFile(oldPath, newPath); return SaveResults.ConvertToExternalResult(result); } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { Result result = SaveDataFileSystemCore.GetEntryType(out entryType, path); return SaveResults.ConvertToExternalResult(result); } - public Result GetFreeSpaceSize(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) { Result result = SaveDataFileSystemCore.GetFreeSpaceSize(out freeSpace, path); return SaveResults.ConvertToExternalResult(result); } - public Result GetTotalSpaceSize(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) { Result result = SaveDataFileSystemCore.GetTotalSpaceSize(out totalSpace, path); return SaveResults.ConvertToExternalResult(result); } - public Result Commit() + protected override Result CommitImpl() { Result result = Commit(Keyset); return SaveResults.ConvertToExternalResult(result); } - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) - { - timeStamp = default; - return ResultFs.NotImplemented.Log(); - } - - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) => - ResultFs.NotImplemented.Log(); - public Result Commit(Keyset keyset) { CoreDataIvfcStorage.Flush(); diff --git a/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs b/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs index 731676ab..5b8fd880 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs @@ -1,10 +1,9 @@ -using System; -using System.IO; +using System.IO; using LibHac.Fs; namespace LibHac.FsSystem.Save { - public class SaveDataFileSystemCore : IFileSystem + public class SaveDataFileSystemCore : FileSystemBase { private IStorage BaseStorage { get; } private IStorage HeaderStorage { get; } @@ -28,7 +27,7 @@ namespace LibHac.FsSystem.Save FileTable = new HierarchicalSaveFileTable(dirTableStorage, fileTableStorage); } - public Result CreateDirectory(string path) + protected override Result CreateDirectoryImpl(string path) { path = PathTools.Normalize(path); @@ -37,7 +36,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result CreateFile(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); @@ -64,7 +63,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result DeleteDirectory(string path) + protected override Result DeleteDirectoryImpl(string path) { path = PathTools.Normalize(path); @@ -73,7 +72,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result DeleteDirectoryRecursively(string path) + protected override Result DeleteDirectoryRecursivelyImpl(string path) { path = PathTools.Normalize(path); @@ -85,7 +84,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result CleanDirectoryRecursively(string path) + protected override Result CleanDirectoryRecursivelyImpl(string path) { path = PathTools.Normalize(path); @@ -94,7 +93,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result DeleteFile(string path) + protected override Result DeleteFileImpl(string path) { path = PathTools.Normalize(path); @@ -113,7 +112,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { directory = default; path = PathTools.Normalize(path); @@ -128,7 +127,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { file = default; path = PathTools.Normalize(path); @@ -145,7 +144,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result RenameDirectory(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(string oldPath, string newPath) { oldPath = PathTools.Normalize(oldPath); newPath = PathTools.Normalize(newPath); @@ -153,7 +152,7 @@ namespace LibHac.FsSystem.Save return FileTable.RenameDirectory(oldPath, newPath); } - public Result RenameFile(string oldPath, string newPath) + protected override Result RenameFileImpl(string oldPath, string newPath) { oldPath = PathTools.Normalize(oldPath); newPath = PathTools.Normalize(newPath); @@ -163,7 +162,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); @@ -183,7 +182,7 @@ namespace LibHac.FsSystem.Save return ResultFs.PathNotFound.Log(); } - public Result GetFreeSpaceSize(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) { int freeBlockCount = AllocationTable.GetFreeListLength(); freeSpace = Header.BlockSize * freeBlockCount; @@ -191,29 +190,18 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public Result GetTotalSpaceSize(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) { totalSpace = Header.BlockSize * Header.BlockCount; return Result.Success; } - public Result Commit() + protected override Result CommitImpl() { return Result.Success; } - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) - { - timeStamp = default; - return ResultFs.NotImplemented.Log(); - } - - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) - { - return ResultFs.NotImplemented.Log(); - } - public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); diff --git a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs index e9bb51f8..8b00bd71 100644 --- a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs +++ b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs @@ -3,7 +3,7 @@ using LibHac.Fs; namespace LibHac.FsSystem { - public class SubdirectoryFileSystem : IFileSystem + public class SubdirectoryFileSystem : FileSystemBase { private string RootPath { get; } private IFileSystem ParentFileSystem { get; } @@ -19,63 +19,63 @@ namespace LibHac.FsSystem RootPath = PathTools.Normalize(rootPath); } - public Result CreateDirectory(string path) + protected override Result CreateDirectoryImpl(string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.CreateDirectory(fullPath); } - public Result CreateFile(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.CreateFile(fullPath, size, options); } - public Result DeleteDirectory(string path) + protected override Result DeleteDirectoryImpl(string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.DeleteDirectory(fullPath); } - public Result DeleteDirectoryRecursively(string path) + protected override Result DeleteDirectoryRecursivelyImpl(string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.DeleteDirectoryRecursively(fullPath); } - public Result CleanDirectoryRecursively(string path) + protected override Result CleanDirectoryRecursivelyImpl(string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.CleanDirectoryRecursively(fullPath); } - public Result DeleteFile(string path) + protected override Result DeleteFileImpl(string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.DeleteFile(fullPath); } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.OpenDirectory(out directory, fullPath, mode); } - public Result OpenFile(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.OpenFile(out file, fullPath, mode); } - public Result RenameDirectory(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(string oldPath, string newPath) { string fullOldPath = ResolveFullPath(PathTools.Normalize(oldPath)); string fullNewPath = ResolveFullPath(PathTools.Normalize(newPath)); @@ -83,7 +83,7 @@ namespace LibHac.FsSystem return ParentFileSystem.RenameDirectory(fullOldPath, fullNewPath); } - public Result RenameFile(string oldPath, string newPath) + protected override Result RenameFileImpl(string oldPath, string newPath) { string fullOldPath = ResolveFullPath(PathTools.Normalize(oldPath)); string fullNewPath = ResolveFullPath(PathTools.Normalize(newPath)); @@ -91,40 +91,40 @@ namespace LibHac.FsSystem return ParentFileSystem.RenameFile(fullOldPath, fullNewPath); } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.GetEntryType(out entryType, fullPath); } - public Result Commit() + protected override Result CommitImpl() { return ParentFileSystem.Commit(); } - public Result GetFreeSpaceSize(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.GetFreeSpaceSize(out freeSpace, fullPath); } - public Result GetTotalSpaceSize(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.GetTotalSpaceSize(out totalSpace, fullPath); } - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); return ParentFileSystem.GetFileTimeStampRaw(out timeStamp, fullPath); } - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { string fullPath = ResolveFullPath(PathTools.Normalize(path)); From 8390e10ae0666529b841b00c406966c8f842f9c5 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 11 Oct 2019 19:13:11 -0500 Subject: [PATCH 45/46] Make FileBase abstract methods protected --- src/LibHac/Fs/Accessors/FileAccessor.cs | 15 +++++++-------- src/LibHac/Fs/FileBase.cs | 10 +++++----- src/LibHac/FsSystem/AesXtsFile.cs | 10 +++++----- src/LibHac/FsSystem/ConcatenationFile.cs | 10 +++++----- src/LibHac/FsSystem/DirectorySaveDataFile.cs | 10 +++++----- src/LibHac/FsSystem/LocalFile.cs | 10 +++++----- src/LibHac/FsSystem/NullFile.cs | 10 +++++----- src/LibHac/FsSystem/PartitionFile.cs | 10 +++++----- src/LibHac/FsSystem/ReadOnlyFile.cs | 10 +++++----- src/LibHac/FsSystem/RomFs/RomFsFile.cs | 10 +++++----- src/LibHac/FsSystem/Save/SaveDataFile.cs | 10 +++++----- src/LibHac/FsSystem/StorageFile.cs | 10 +++++----- src/LibHac/FsSystem/StreamFile.cs | 10 +++++----- 13 files changed, 67 insertions(+), 68 deletions(-) diff --git a/src/LibHac/Fs/Accessors/FileAccessor.cs b/src/LibHac/Fs/Accessors/FileAccessor.cs index da052d71..030a0e8b 100644 --- a/src/LibHac/Fs/Accessors/FileAccessor.cs +++ b/src/LibHac/Fs/Accessors/FileAccessor.cs @@ -2,7 +2,7 @@ namespace LibHac.Fs.Accessors { - public class FileAccessor : IFile + public class FileAccessor : FileBase { private IFile File { get; set; } @@ -17,14 +17,14 @@ namespace LibHac.Fs.Accessors OpenMode = mode; } - public Result Read(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { CheckIfDisposed(); return File.Read(out bytesRead, offset, destination, options); } - public Result Write(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { CheckIfDisposed(); @@ -35,7 +35,6 @@ namespace LibHac.Fs.Accessors return Result.Success; } - // Result rc = File.Write(offset, source, options); if (rc.IsSuccess()) @@ -46,7 +45,7 @@ namespace LibHac.Fs.Accessors return rc; } - public Result Flush() + protected override Result FlushImpl() { CheckIfDisposed(); @@ -60,21 +59,21 @@ namespace LibHac.Fs.Accessors return rc; } - public Result GetSize(out long size) + protected override Result GetSizeImpl(out long size) { CheckIfDisposed(); return File.GetSize(out size); } - public Result SetSize(long size) + protected override Result SetSizeImpl(long size) { CheckIfDisposed(); return File.SetSize(size); } - public void Dispose() + protected override void Dispose(bool disposing) { if (File == null) return; diff --git a/src/LibHac/Fs/FileBase.cs b/src/LibHac/Fs/FileBase.cs index 6aec6529..ab48f665 100644 --- a/src/LibHac/Fs/FileBase.cs +++ b/src/LibHac/Fs/FileBase.cs @@ -9,11 +9,11 @@ namespace LibHac.Fs private int _disposedState; private bool IsDisposed => _disposedState != 0; - public abstract Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options); - public abstract Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options); - public abstract Result FlushImpl(); - public abstract Result GetSizeImpl(out long size); - public abstract Result SetSizeImpl(long size); + protected abstract Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options); + protected abstract Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options); + protected abstract Result FlushImpl(); + protected abstract Result GetSizeImpl(out long size); + protected abstract Result SetSizeImpl(long size); public Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { diff --git a/src/LibHac/FsSystem/AesXtsFile.cs b/src/LibHac/FsSystem/AesXtsFile.cs index 9455126a..e4308efb 100644 --- a/src/LibHac/FsSystem/AesXtsFile.cs +++ b/src/LibHac/FsSystem/AesXtsFile.cs @@ -53,7 +53,7 @@ namespace LibHac.FsSystem return key; } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; @@ -67,7 +67,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); if (rc.IsFailure()) return rc; @@ -89,18 +89,18 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result FlushImpl() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = Header.Size; return Result.Success; } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { Header.SetSize(size, VerificationKey); diff --git a/src/LibHac/FsSystem/ConcatenationFile.cs b/src/LibHac/FsSystem/ConcatenationFile.cs index 81f2598d..9165a36e 100644 --- a/src/LibHac/FsSystem/ConcatenationFile.cs +++ b/src/LibHac/FsSystem/ConcatenationFile.cs @@ -33,7 +33,7 @@ namespace LibHac.FsSystem } } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; @@ -69,7 +69,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { Result rc = ValidateWriteParams(offset, source.Length, Mode, out _); if (rc.IsFailure()) return rc; @@ -105,7 +105,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result FlushImpl() + protected override Result FlushImpl() { foreach (IFile file in Sources) { @@ -116,7 +116,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = default; @@ -131,7 +131,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { Result rc = GetSize(out long currentSize); if (rc.IsFailure()) return rc; diff --git a/src/LibHac/FsSystem/DirectorySaveDataFile.cs b/src/LibHac/FsSystem/DirectorySaveDataFile.cs index 053c4c75..de54607d 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFile.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFile.cs @@ -16,27 +16,27 @@ namespace LibHac.FsSystem Mode = mode; } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { return BaseFile.Read(out bytesRead, offset, destination, options); } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { return BaseFile.Write(offset, source, options); } - public override Result FlushImpl() + protected override Result FlushImpl() { return BaseFile.Flush(); } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { return BaseFile.GetSize(out size); } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { return BaseFile.SetSize(size); } diff --git a/src/LibHac/FsSystem/LocalFile.cs b/src/LibHac/FsSystem/LocalFile.cs index 6a56d1d8..6e922cc0 100644 --- a/src/LibHac/FsSystem/LocalFile.cs +++ b/src/LibHac/FsSystem/LocalFile.cs @@ -27,7 +27,7 @@ namespace LibHac.FsSystem File = new StreamFile(Stream, mode); } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = 0; @@ -37,7 +37,7 @@ namespace LibHac.FsSystem return File.Read(out bytesRead, offset, destination.Slice(0, (int)toRead), options); } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { Result rc = ValidateWriteParams(offset, source.Length, Mode, out _); if (rc.IsFailure()) return rc; @@ -45,7 +45,7 @@ namespace LibHac.FsSystem return File.Write(offset, source, options); } - public override Result FlushImpl() + protected override Result FlushImpl() { try { @@ -57,7 +57,7 @@ namespace LibHac.FsSystem } } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { try { @@ -70,7 +70,7 @@ namespace LibHac.FsSystem } } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { try { diff --git a/src/LibHac/FsSystem/NullFile.cs b/src/LibHac/FsSystem/NullFile.cs index 44c79721..4bfdbcf7 100644 --- a/src/LibHac/FsSystem/NullFile.cs +++ b/src/LibHac/FsSystem/NullFile.cs @@ -16,7 +16,7 @@ namespace LibHac.FsSystem private long Length { get; } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = 0; @@ -29,23 +29,23 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { return Result.Success; } - public override Result FlushImpl() + protected override Result FlushImpl() { return Result.Success; } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = Length; return Result.Success; } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperation.Log(); } diff --git a/src/LibHac/FsSystem/PartitionFile.cs b/src/LibHac/FsSystem/PartitionFile.cs index 12468d96..7206fc9d 100644 --- a/src/LibHac/FsSystem/PartitionFile.cs +++ b/src/LibHac/FsSystem/PartitionFile.cs @@ -18,7 +18,7 @@ namespace LibHac.FsSystem Size = size; } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = 0; @@ -32,7 +32,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); if (rc.IsFailure()) return rc; @@ -53,7 +53,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result FlushImpl() + protected override Result FlushImpl() { if (!Mode.HasFlag(OpenMode.Write)) { @@ -63,13 +63,13 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = Size; return Result.Success; } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { if (!Mode.HasFlag(OpenMode.Write)) { diff --git a/src/LibHac/FsSystem/ReadOnlyFile.cs b/src/LibHac/FsSystem/ReadOnlyFile.cs index 8945f1be..211f9d4d 100644 --- a/src/LibHac/FsSystem/ReadOnlyFile.cs +++ b/src/LibHac/FsSystem/ReadOnlyFile.cs @@ -12,27 +12,27 @@ namespace LibHac.FsSystem BaseFile = baseFile; } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { return BaseFile.Read(out bytesRead, offset, destination, options); } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { return BaseFile.GetSize(out size); } - public override Result FlushImpl() + protected override Result FlushImpl() { return Result.Success; } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { return ResultFs.InvalidOpenModeForWrite.Log(); } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { return ResultFs.InvalidOpenModeForWrite.Log(); } diff --git a/src/LibHac/FsSystem/RomFs/RomFsFile.cs b/src/LibHac/FsSystem/RomFs/RomFsFile.cs index 3f304868..11d05b38 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsFile.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsFile.cs @@ -16,7 +16,7 @@ namespace LibHac.FsSystem.RomFs Size = size; } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; @@ -33,23 +33,23 @@ namespace LibHac.FsSystem.RomFs return Result.Success; } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } - public override Result FlushImpl() + protected override Result FlushImpl() { return Result.Success; } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = Size; return Result.Success; } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { return ResultFs.UnsupportedOperationModifyRomFsFile.Log(); } diff --git a/src/LibHac/FsSystem/Save/SaveDataFile.cs b/src/LibHac/FsSystem/Save/SaveDataFile.cs index 93b7d07e..6310bff1 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFile.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFile.cs @@ -21,7 +21,7 @@ namespace LibHac.FsSystem.Save Size = size; } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; @@ -41,7 +41,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); if (rc.IsFailure()) return rc; @@ -62,18 +62,18 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public override Result FlushImpl() + protected override Result FlushImpl() { return BaseStorage.Flush(); } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { size = Size; return Result.Success; } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { if (size < 0) throw new ArgumentOutOfRangeException(nameof(size)); if (Size == size) return Result.Success; diff --git a/src/LibHac/FsSystem/StorageFile.cs b/src/LibHac/FsSystem/StorageFile.cs index 604dfd6c..96d23a30 100644 --- a/src/LibHac/FsSystem/StorageFile.cs +++ b/src/LibHac/FsSystem/StorageFile.cs @@ -14,7 +14,7 @@ namespace LibHac.FsSystem Mode = mode; } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; @@ -34,7 +34,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { Result rc = ValidateWriteParams(offset, source.Length, Mode, out bool isResizeNeeded); if (rc.IsFailure()) return rc; @@ -56,7 +56,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result FlushImpl() + protected override Result FlushImpl() { if (!Mode.HasFlag(OpenMode.Write)) return Result.Success; @@ -64,12 +64,12 @@ namespace LibHac.FsSystem return BaseStorage.Flush(); } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { return BaseStorage.GetSize(out size); } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { if (!Mode.HasFlag(OpenMode.Write)) return ResultFs.InvalidOpenModeForWrite.Log(); diff --git a/src/LibHac/FsSystem/StreamFile.cs b/src/LibHac/FsSystem/StreamFile.cs index 90db129d..5114af65 100644 --- a/src/LibHac/FsSystem/StreamFile.cs +++ b/src/LibHac/FsSystem/StreamFile.cs @@ -25,7 +25,7 @@ namespace LibHac.FsSystem Mode = mode; } - public override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) + protected override Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options) { bytesRead = default; @@ -65,7 +65,7 @@ namespace LibHac.FsSystem #endif } - public override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) + protected override Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options) { Result rc = ValidateWriteParams(offset, source.Length, Mode, out _); if (rc.IsFailure()) return rc; @@ -99,7 +99,7 @@ namespace LibHac.FsSystem return Result.Success; } - public override Result FlushImpl() + protected override Result FlushImpl() { lock (Locker) { @@ -108,7 +108,7 @@ namespace LibHac.FsSystem } } - public override Result GetSizeImpl(out long size) + protected override Result GetSizeImpl(out long size) { lock (Locker) { @@ -117,7 +117,7 @@ namespace LibHac.FsSystem } } - public override Result SetSizeImpl(long size) + protected override Result SetSizeImpl(long size) { lock (Locker) { From 576049ce8803964a047390d9b2015ef0cbe92fe6 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 11 Oct 2019 21:13:16 -0500 Subject: [PATCH 46/46] Add OperateRange to IFile and IStorage. Reorder methods --- src/LibHac/Fs/FileBase.cs | 22 ++++- src/LibHac/Fs/FileSystemBase.cs | 46 +++++------ src/LibHac/Fs/FsEnums.cs | 8 ++ src/LibHac/Fs/IFile.cs | 18 +++- src/LibHac/Fs/IFileSystem.cs | 142 ++++++++++++++++---------------- src/LibHac/Fs/IStorage.cs | 12 +++ src/LibHac/Fs/StorageBase.cs | 14 ++++ 7 files changed, 161 insertions(+), 101 deletions(-) diff --git a/src/LibHac/Fs/FileBase.cs b/src/LibHac/Fs/FileBase.cs index ab48f665..c8126bd4 100644 --- a/src/LibHac/Fs/FileBase.cs +++ b/src/LibHac/Fs/FileBase.cs @@ -12,8 +12,14 @@ namespace LibHac.Fs protected abstract Result ReadImpl(out long bytesRead, long offset, Span destination, ReadOption options); protected abstract Result WriteImpl(long offset, ReadOnlySpan source, WriteOption options); protected abstract Result FlushImpl(); - protected abstract Result GetSizeImpl(out long size); protected abstract Result SetSizeImpl(long size); + protected abstract Result GetSizeImpl(out long size); + + protected virtual Result OperateRangeImpl(Span outBuffer, OperationId operationId, long offset, long size, + ReadOnlySpan inBuffer) + { + return ResultFs.NotImplemented.Log(); + } public Result Read(out long bytesRead, long offset, Span destination, ReadOption options) { @@ -53,6 +59,14 @@ namespace LibHac.Fs return FlushImpl(); } + public Result SetSize(long size) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + if (size < 0) return ResultFs.ValueOutOfRange.Log(); + + return SetSizeImpl(size); + } + public Result GetSize(out long size) { if (IsDisposed) @@ -64,12 +78,12 @@ namespace LibHac.Fs return GetSizeImpl(out size); } - public Result SetSize(long size) + public Result OperateRange(Span outBuffer, OperationId operationId, long offset, long size, + ReadOnlySpan inBuffer) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); - if (size < 0) return ResultFs.ValueOutOfRange.Log(); - return SetSizeImpl(size); + return OperateRange(outBuffer, operationId, offset, size, inBuffer); } public void Dispose() diff --git a/src/LibHac/Fs/FileSystemBase.cs b/src/LibHac/Fs/FileSystemBase.cs index 3f6ec78f..889cad2e 100644 --- a/src/LibHac/Fs/FileSystemBase.cs +++ b/src/LibHac/Fs/FileSystemBase.cs @@ -22,6 +22,29 @@ namespace LibHac.Fs protected abstract Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path); protected abstract Result CommitImpl(); + protected virtual Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + { + freeSpace = default; + return ResultFs.NotImplemented.Log(); + } + + protected virtual Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + { + totalSpace = default; + return ResultFs.NotImplemented.Log(); + } + + protected virtual Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) + { + timeStamp = default; + return ResultFs.NotImplemented.Log(); + } + + protected virtual Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + { + return ResultFs.NotImplemented.Log(); + } + public Result CreateDirectory(string path) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); @@ -169,28 +192,5 @@ namespace LibHac.Fs } protected virtual void Dispose(bool disposing) { } - - protected virtual Result GetFreeSpaceSizeImpl(out long freeSpace, string path) - { - freeSpace = default; - return ResultFs.NotImplemented.Log(); - } - - protected virtual Result GetTotalSpaceSizeImpl(out long totalSpace, string path) - { - totalSpace = default; - return ResultFs.NotImplemented.Log(); - } - - protected virtual Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) - { - timeStamp = default; - return ResultFs.NotImplemented.Log(); - } - - protected virtual Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) - { - return ResultFs.NotImplemented.Log(); - } } } diff --git a/src/LibHac/Fs/FsEnums.cs b/src/LibHac/Fs/FsEnums.cs index 08758ff7..ba9485b6 100644 --- a/src/LibHac/Fs/FsEnums.cs +++ b/src/LibHac/Fs/FsEnums.cs @@ -119,4 +119,12 @@ namespace LibHac.Fs None = 0, Flush = 1 } + + public enum OperationId + { + Clear = 0, + ClearSignature = 1, + InvalidateCache = 2, + QueryRange = 3 + } } diff --git a/src/LibHac/Fs/IFile.cs b/src/LibHac/Fs/IFile.cs index 1c98e082..29746104 100644 --- a/src/LibHac/Fs/IFile.cs +++ b/src/LibHac/Fs/IFile.cs @@ -44,6 +44,13 @@ namespace LibHac.Fs /// Result Flush(); + /// + /// Sets the size of the file in bytes. + /// + /// The desired size of the file in bytes. + /// The of the requested operation. + Result SetSize(long size); + /// /// Gets the number of bytes in the file. /// @@ -52,10 +59,15 @@ namespace LibHac.Fs Result GetSize(out long size); /// - /// Sets the size of the file in bytes. + /// Performs various operations on the file. Used to extend the functionality of the interface. /// - /// The desired size of the file in bytes. + /// A buffer that will contain the response from the operation. + /// The operation to be performed. + /// The offset of the range to operate on. + /// The size of the range to operate on. + /// An input buffer. Size may vary depending on the operation performed. /// The of the requested operation. - Result SetSize(long size); + Result OperateRange(Span outBuffer, OperationId operationId, long offset, long size, + ReadOnlySpan inBuffer); } } \ No newline at end of file diff --git a/src/LibHac/Fs/IFileSystem.cs b/src/LibHac/Fs/IFileSystem.cs index 5e6275b6..91721465 100644 --- a/src/LibHac/Fs/IFileSystem.cs +++ b/src/LibHac/Fs/IFileSystem.cs @@ -8,20 +8,6 @@ namespace LibHac.Fs /// public interface IFileSystem { - /// - /// Creates all directories and subdirectories in the specified path unless they already exist. - /// - /// The full path of the directory to create. - /// The of the requested operation. - /// - /// The following codes may be returned under certain conditions: - /// - /// The parent directory of the specified path does not exist: - /// Specified path already exists as either a file or directory: - /// Insufficient free space to create the directory: - /// - Result CreateDirectory(string path); - /// /// Creates or overwrites a file at the specified path. /// @@ -39,6 +25,32 @@ namespace LibHac.Fs /// Result CreateFile(string path, long size, CreateFileOptions options); + /// + /// Deletes the specified file. + /// + /// The full path of the file to delete. + /// The of the requested operation. + /// + /// The following codes may be returned under certain conditions: + /// + /// The specified path does not exist or is a directory: + /// + Result DeleteFile(string path); + + /// + /// Creates all directories and subdirectories in the specified path unless they already exist. + /// + /// The full path of the directory to create. + /// The of the requested operation. + /// + /// The following codes may be returned under certain conditions: + /// + /// The parent directory of the specified path does not exist: + /// Specified path already exists as either a file or directory: + /// Insufficient free space to create the directory: + /// + Result CreateDirectory(string path); + /// /// Deletes the specified directory. /// @@ -77,46 +89,20 @@ namespace LibHac.Fs Result CleanDirectoryRecursively(string path); /// - /// Deletes the specified file. + /// Renames or moves a file to a new location. /// - /// The full path of the file to delete. + /// The full path of the file to rename. + /// The new full path of the file. /// The of the requested operation. /// + /// If and are the same, this function does nothing and returns successfully. /// The following codes may be returned under certain conditions: /// - /// The specified path does not exist or is a directory: + /// does not exist or is a directory: + /// 's parent directory does not exist: + /// already exists as either a file or directory: /// - Result DeleteFile(string path); - - /// - /// Creates an instance for enumerating the specified directory. - /// - /// If the operation returns successfully, - /// An instance for the specified directory. - /// The directory's full path. - /// Specifies which sub-entries should be enumerated. - /// The of the requested operation. - /// - /// The following codes may be returned under certain conditions: - /// - /// The specified path does not exist or is a file: - /// - Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode); - - /// - /// Opens an instance for the specified path. - /// - /// If the operation returns successfully, - /// An instance for the specified path. - /// The full path of the file to open. - /// Specifies the access permissions of the created . - /// The of the requested operation. - /// - /// The following codes may be returned under certain conditions: - /// - /// The specified path does not exist or is a directory: - /// - Result OpenFile(out IFile file, string path, OpenMode mode); + Result RenameFile(string oldPath, string newPath); /// /// Renames or moves a directory to a new location. @@ -135,22 +121,6 @@ namespace LibHac.Fs /// Result RenameDirectory(string oldPath, string newPath); - /// - /// Renames or moves a file to a new location. - /// - /// The full path of the file to rename. - /// The new full path of the file. - /// The of the requested operation. - /// - /// If and are the same, this function does nothing and returns successfully. - /// The following codes may be returned under certain conditions: - /// - /// does not exist or is a directory: - /// 's parent directory does not exist: - /// already exists as either a file or directory: - /// - Result RenameFile(string oldPath, string newPath); - /// /// Determines whether the specified path is a file or directory, or does not exist. /// @@ -180,6 +150,43 @@ namespace LibHac.Fs /// The of the requested operation. Result GetTotalSpaceSize(out long totalSpace, string path); + /// + /// Opens an instance for the specified path. + /// + /// If the operation returns successfully, + /// An instance for the specified path. + /// The full path of the file to open. + /// Specifies the access permissions of the created . + /// The of the requested operation. + /// + /// The following codes may be returned under certain conditions: + /// + /// The specified path does not exist or is a directory: + /// + Result OpenFile(out IFile file, string path, OpenMode mode); + + /// + /// Creates an instance for enumerating the specified directory. + /// + /// If the operation returns successfully, + /// An instance for the specified directory. + /// The directory's full path. + /// Specifies which sub-entries should be enumerated. + /// The of the requested operation. + /// + /// The following codes may be returned under certain conditions: + /// + /// The specified path does not exist or is a file: + /// + Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode); + + /// + /// Commits any changes to a transactional file system. + /// Does nothing if called on a non-transactional file system. + /// + /// The of the requested operation. + Result Commit(); + /// /// Gets the creation, last accessed, and last modified timestamps of a file or directory. /// @@ -194,13 +201,6 @@ namespace LibHac.Fs /// Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path); - /// - /// Commits any changes to a transactional file system. - /// Does nothing if called on a non-transactional file system. - /// - /// The of the requested operation. - Result Commit(); - /// /// Performs a query on the specified file. /// diff --git a/src/LibHac/Fs/IStorage.cs b/src/LibHac/Fs/IStorage.cs index 8f0a1b47..455388ef 100644 --- a/src/LibHac/Fs/IStorage.cs +++ b/src/LibHac/Fs/IStorage.cs @@ -42,5 +42,17 @@ namespace LibHac.Fs /// /// The size of the in bytes. Result GetSize(out long size); + + /// + /// Performs various operations on the file. Used to extend the functionality of the interface. + /// + /// A buffer that will contain the response from the operation. + /// The operation to be performed. + /// The offset of the range to operate on. + /// The size of the range to operate on. + /// An input buffer. Size may vary depending on the operation performed. + /// The of the requested operation. + Result OperateRange(Span outBuffer, OperationId operationId, long offset, long size, + ReadOnlySpan inBuffer); } } diff --git a/src/LibHac/Fs/StorageBase.cs b/src/LibHac/Fs/StorageBase.cs index 33044952..f764494f 100644 --- a/src/LibHac/Fs/StorageBase.cs +++ b/src/LibHac/Fs/StorageBase.cs @@ -15,6 +15,12 @@ namespace LibHac.Fs protected abstract Result GetSizeImpl(out long size); protected abstract Result SetSizeImpl(long size); + protected virtual Result OperateRangeImpl(Span outBuffer, OperationId operationId, long offset, long size, + ReadOnlySpan inBuffer) + { + return ResultFs.NotImplemented.Log(); + } + public Result Read(long offset, Span destination) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); @@ -51,6 +57,14 @@ namespace LibHac.Fs return GetSizeImpl(out size); } + public Result OperateRange(Span outBuffer, OperationId operationId, long offset, long size, + ReadOnlySpan inBuffer) + { + if (IsDisposed) return ResultFs.PreconditionViolation.Log(); + + return OperateRange(outBuffer, operationId, offset, size, inBuffer); + } + public void Dispose() { // Make sure Dispose is only called once