From f3452bb314b4d8d2e1aa5fe0e2e7581436a5d740 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 11 Apr 2020 22:18:43 -0700 Subject: [PATCH] BCAT fixes. Tweak how U8StringBuilder is used --- src/LibHac/Bcat/BcatServer.cs | 5 +- .../Ipc/IDeliveryCacheDirectoryService.cs | 2 +- .../Detail/Ipc/IDeliveryCacheFileService.cs | 2 +- .../Ipc/IDeliveryCacheStorageService.cs | 2 +- .../Core/DeliveryCacheStorageManager.cs | 30 +-- .../Service/DeliveryCacheDirectoryService.cs | 4 +- .../Service/DeliveryCacheFileService.cs | 4 +- .../Service/DeliveryCacheStorageService.cs | 4 +- .../Bcat/Detail/Service/ServiceCreator.cs | 13 +- src/LibHac/Common/StringUtils.cs | 2 +- src/LibHac/Common/U8StringBuilder.cs | 201 ++++++++++++------ src/LibHac/Fs/Shim/Bis.cs | 10 +- src/LibHac/Fs/Shim/Host.cs | 7 +- src/LibHac/FsSystem/FsPath.cs | 5 +- src/LibHac/Horizon.cs | 18 +- 15 files changed, 200 insertions(+), 109 deletions(-) diff --git a/src/LibHac/Bcat/BcatServer.cs b/src/LibHac/Bcat/BcatServer.cs index 2618967d..b2c13c9e 100644 --- a/src/LibHac/Bcat/BcatServer.cs +++ b/src/LibHac/Bcat/BcatServer.cs @@ -32,7 +32,7 @@ namespace LibHac.Bcat public Result GetServiceCreator(out IServiceCreator serviceCreator, BcatServiceType type) { - if ((uint)type < ServiceTypeCount) + if ((uint)type >= ServiceTypeCount) { serviceCreator = default; return ResultLibHac.ArgumentOutOfRange.Log(); @@ -87,6 +87,9 @@ namespace LibHac.Bcat if (!rc.IsSuccess()) throw new HorizonResultException(rc, "Abort"); + fsClient.SetAccessLogTarget(AccessLogTarget.All); + + FsClient = fsClient; return fsClient; } } diff --git a/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheDirectoryService.cs b/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheDirectoryService.cs index 26ff37db..0e064361 100644 --- a/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheDirectoryService.cs +++ b/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheDirectoryService.cs @@ -2,7 +2,7 @@ namespace LibHac.Bcat.Detail.Ipc { - public interface IDeliveryCacheDirectoryService + public interface IDeliveryCacheDirectoryService : IDisposable { Result Open(ref DirectoryName name); Result Read(out int entriesRead, Span entryBuffer); diff --git a/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheFileService.cs b/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheFileService.cs index ae381047..0956f7d2 100644 --- a/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheFileService.cs +++ b/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheFileService.cs @@ -2,7 +2,7 @@ namespace LibHac.Bcat.Detail.Ipc { - public interface IDeliveryCacheFileService + public interface IDeliveryCacheFileService : IDisposable { Result Open(ref DirectoryName directoryName, ref FileName fileName); Result Read(out long bytesRead, long offset, Span destination); diff --git a/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheStorageService.cs b/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheStorageService.cs index 8a4bad3e..4429c1af 100644 --- a/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheStorageService.cs +++ b/src/LibHac/Bcat/Detail/Ipc/IDeliveryCacheStorageService.cs @@ -2,7 +2,7 @@ namespace LibHac.Bcat.Detail.Ipc { - public interface IDeliveryCacheStorageService + public interface IDeliveryCacheStorageService : IDisposable { Result CreateFileService(out IDeliveryCacheFileService fileService); Result CreateDirectoryService(out IDeliveryCacheDirectoryService directoryService); diff --git a/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheStorageManager.cs b/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheStorageManager.cs index ecd76e0c..2d219f1a 100644 --- a/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheStorageManager.cs +++ b/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheStorageManager.cs @@ -48,8 +48,8 @@ namespace LibHac.Bcat.Detail.Service.Core // Get the mount name var mountName = new MountName(); - new U8StringBuilder(mountName.Name) - .Append(DeliveryCacheMountNamePrefix) + var sb = new U8StringBuilder(mountName.Name); + sb.Append(DeliveryCacheMountNamePrefix) .AppendFormat(index, 'd', 2); // Mount the save if enabled @@ -89,8 +89,8 @@ namespace LibHac.Bcat.Detail.Service.Core { var mountName = new MountName(); - new U8StringBuilder(mountName.Name) - .Append(DeliveryCacheMountNamePrefix) + var sb = new U8StringBuilder(mountName.Name); + sb.Append(DeliveryCacheMountNamePrefix) .AppendFormat(index, 'd', 2); // Unmount the entry's savedata @@ -115,8 +115,8 @@ namespace LibHac.Bcat.Detail.Service.Core var mountName = new MountName(); - new U8StringBuilder(mountName.Name) - .Append(DeliveryCacheMountNamePrefix) + var sb = new U8StringBuilder(mountName.Name); + sb.Append(DeliveryCacheMountNamePrefix) .AppendFormat(index, 'd', 2); if (!DisableStorage) @@ -215,10 +215,10 @@ namespace LibHac.Bcat.Detail.Service.Core var sb = new U8StringBuilder(pathBuffer); AppendMountName(ref sb, applicationId); - sb.Append(DirectoriesPath); - sb.Append(DirectorySeparator).Append(directoryName.Bytes); - sb.Append(DirectorySeparator).Append(FilesDirectoryName); - sb.Append(DirectorySeparator).Append(fileName.Bytes); + sb.Append(DirectoriesPath) + .Append(DirectorySeparator).Append(directoryName.Bytes) + .Append(DirectorySeparator).Append(FilesDirectoryName) + .Append(DirectorySeparator).Append(fileName.Bytes); } } @@ -229,9 +229,9 @@ namespace LibHac.Bcat.Detail.Service.Core var sb = new U8StringBuilder(pathBuffer); AppendMountName(ref sb, applicationId); - sb.Append(DirectoriesPath); - sb.Append(DirectorySeparator).Append(directoryName.Bytes); - sb.Append(DirectorySeparator).Append(FilesMetaFileName); + sb.Append(DirectoriesPath) + .Append(DirectorySeparator).Append(directoryName.Bytes) + .Append(DirectorySeparator).Append(FilesMetaFileName); } } @@ -252,8 +252,8 @@ namespace LibHac.Bcat.Detail.Service.Core var sb = new U8StringBuilder(pathBuffer); AppendMountName(ref sb, applicationId); - sb.Append(DirectoriesPath); - sb.Append(DirectorySeparator).Append(directoryName.Bytes); + sb.Append(DirectoriesPath) + .Append(DirectorySeparator).Append(directoryName.Bytes); } } diff --git a/src/LibHac/Bcat/Detail/Service/DeliveryCacheDirectoryService.cs b/src/LibHac/Bcat/Detail/Service/DeliveryCacheDirectoryService.cs index bbeb1a3d..17416413 100644 --- a/src/LibHac/Bcat/Detail/Service/DeliveryCacheDirectoryService.cs +++ b/src/LibHac/Bcat/Detail/Service/DeliveryCacheDirectoryService.cs @@ -4,11 +4,13 @@ using LibHac.Bcat.Detail.Service.Core; namespace LibHac.Bcat.Detail.Service { - internal class DeliveryCacheDirectoryService : IDeliveryCacheDirectoryService, IDisposable + internal class DeliveryCacheDirectoryService : IDeliveryCacheDirectoryService { private BcatServer Server { get; } private object Locker { get; } = new object(); private DeliveryCacheStorageService Parent { get; } + + // ReSharper disable once UnusedAutoPropertyAccessor.Local private AccessControl Access { get; } private ulong ApplicationId { get; } private DirectoryName _name; diff --git a/src/LibHac/Bcat/Detail/Service/DeliveryCacheFileService.cs b/src/LibHac/Bcat/Detail/Service/DeliveryCacheFileService.cs index b39cd62f..a4f65911 100644 --- a/src/LibHac/Bcat/Detail/Service/DeliveryCacheFileService.cs +++ b/src/LibHac/Bcat/Detail/Service/DeliveryCacheFileService.cs @@ -6,11 +6,13 @@ using LibHac.Fs; namespace LibHac.Bcat.Detail.Service { - internal class DeliveryCacheFileService : IDeliveryCacheFileService, IDisposable + internal class DeliveryCacheFileService : IDeliveryCacheFileService { private BcatServer Server { get; } private object Locker { get; } = new object(); private DeliveryCacheStorageService Parent { get; } + + // ReSharper disable once UnusedAutoPropertyAccessor.Local private AccessControl Access { get; } private ulong ApplicationId { get; } private FileHandle _handle; diff --git a/src/LibHac/Bcat/Detail/Service/DeliveryCacheStorageService.cs b/src/LibHac/Bcat/Detail/Service/DeliveryCacheStorageService.cs index 2c13bd4b..2ee0d976 100644 --- a/src/LibHac/Bcat/Detail/Service/DeliveryCacheStorageService.cs +++ b/src/LibHac/Bcat/Detail/Service/DeliveryCacheStorageService.cs @@ -4,12 +4,12 @@ using LibHac.Bcat.Detail.Ipc; namespace LibHac.Bcat.Detail.Service { - internal class DeliveryCacheStorageService : IDeliveryCacheStorageService, IDisposable + internal class DeliveryCacheStorageService : IDeliveryCacheStorageService { private const int MaxOpenCount = 8; private BcatServer Server { get; } - public object Locker { get; } = new object(); + private object Locker { get; } = new object(); private AccessControl Access { get; } private ulong ApplicationId { get; } private int FileServiceOpenCount { get; set; } diff --git a/src/LibHac/Bcat/Detail/Service/ServiceCreator.cs b/src/LibHac/Bcat/Detail/Service/ServiceCreator.cs index 0905d706..eaf5039d 100644 --- a/src/LibHac/Bcat/Detail/Service/ServiceCreator.cs +++ b/src/LibHac/Bcat/Detail/Service/ServiceCreator.cs @@ -6,6 +6,8 @@ namespace LibHac.Bcat.Detail.Service internal class ServiceCreator : IServiceCreator { private BcatServer Server { get; } + + // ReSharper disable once UnusedAutoPropertyAccessor.Local private BcatServiceType ServiceType { get; } private AccessControl AccessControl { get; } @@ -35,16 +37,9 @@ namespace LibHac.Bcat.Detail.Service Result rc = Server.GetStorageManager().Open(applicationId.Value); if (rc.IsFailure()) return rc; - try - { - // todo: Check if network account required + // todo: Check if network account required - service = new DeliveryCacheStorageService(Server, applicationId.Value, AccessControl); - } - finally - { - Server.GetStorageManager().Release(applicationId.Value); - } + service = new DeliveryCacheStorageService(Server, applicationId.Value, AccessControl); return Result.Success; } diff --git a/src/LibHac/Common/StringUtils.cs b/src/LibHac/Common/StringUtils.cs index 372b559b..4f548869 100644 --- a/src/LibHac/Common/StringUtils.cs +++ b/src/LibHac/Common/StringUtils.cs @@ -171,7 +171,7 @@ namespace LibHac.Common public static bool IsAlpha(byte c) { - return (c | 0x20u) - (byte)'A' <= 'Z' - 'A'; + return (c | 0x20u) - (byte)'a' <= 'z' - 'a'; } public static bool IsDigit(byte c) diff --git a/src/LibHac/Common/U8StringBuilder.cs b/src/LibHac/Common/U8StringBuilder.cs index 0f78f448..25b24ea7 100644 --- a/src/LibHac/Common/U8StringBuilder.cs +++ b/src/LibHac/Common/U8StringBuilder.cs @@ -10,18 +10,15 @@ namespace LibHac.Common { private const int NullTerminatorLength = 1; - private readonly Span _buffer; - private int _length; - + public Span Buffer { get; } + public int Length { get; private set; } public bool Overflowed { get; private set; } - public readonly int Length => _length; - public readonly int Capacity => _buffer.Length - NullTerminatorLength; - public readonly Span Buffer => _buffer; + public readonly int Capacity => Buffer.Length - NullTerminatorLength; public U8StringBuilder(Span buffer) { - _buffer = buffer; - _length = 0; + Buffer = buffer; + Length = 0; Overflowed = false; ThrowIfBufferLengthIsZero(); @@ -29,70 +26,69 @@ namespace LibHac.Common AddNullTerminator(); } - public U8StringBuilder Append(ReadOnlySpan value) + // These functions are internal so they can be called by the extension methods + // in U8StringBuilderExtensions. It's not an ideal setup, but it allows append + // calls to be chained without accidentally creating a copy of the U8StringBuilder. + internal void AppendInternal(ReadOnlySpan value) { - if (Overflowed) return this; + if (Overflowed) return; int valueLength = StringUtils.GetLength(value); if (!HasAdditionalCapacity(valueLength)) { Overflowed = true; - return this; + return; } - value.Slice(0, valueLength).CopyTo(_buffer.Slice(_length)); - _length += valueLength; + value.Slice(0, valueLength).CopyTo(Buffer.Slice(Length)); + Length += valueLength; AddNullTerminator(); - - return this; } - public U8StringBuilder Append(byte value) + internal void AppendInternal(byte value) { - if (Overflowed) return this; + if (Overflowed) return; if (!HasAdditionalCapacity(1)) { Overflowed = true; - return this; + return; } - _buffer[_length] = value; - _length++; + Buffer[Length] = value; + Length++; AddNullTerminator(); - - return this; } - public U8StringBuilder AppendFormat(byte value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(byte value, char format = 'G', byte precision = 255) => AppendFormatUInt64(value, format, precision); - public U8StringBuilder AppendFormat(sbyte value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(sbyte value, char format = 'G', byte precision = 255) => AppendFormatInt64(value, 0xff, format, precision); - public U8StringBuilder AppendFormat(ushort value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(ushort value, char format = 'G', byte precision = 255) => AppendFormatUInt64(value, format, precision); - public U8StringBuilder AppendFormat(short value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(short value, char format = 'G', byte precision = 255) => AppendFormatInt64(value, 0xffff, format, precision); - public U8StringBuilder AppendFormat(uint value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(uint value, char format = 'G', byte precision = 255) => AppendFormatUInt64(value, format, precision); - public U8StringBuilder AppendFormat(int value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(int value, char format = 'G', byte precision = 255) => AppendFormatInt64(value, 0xffffff, format, precision); - public U8StringBuilder AppendFormat(ulong value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(ulong value, char format = 'G', byte precision = 255) => AppendFormatUInt64(value, format, precision); - public U8StringBuilder AppendFormat(long value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(long value, char format = 'G', byte precision = 255) => AppendFormatInt64(value, 0xffffffff, format, precision); - public U8StringBuilder AppendFormat(float value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(float value, char format = 'G', byte precision = 255) => AppendFormatFloat(value, format, precision); - public U8StringBuilder AppendFormat(double value, char format = 'G', byte precision = 255) => + internal void AppendFormatInternal(double value, char format = 'G', byte precision = 255) => AppendFormatDouble(value, format, precision); private readonly bool HasCapacity(int requiredCapacity) @@ -102,22 +98,22 @@ namespace LibHac.Common private readonly bool HasAdditionalCapacity(int requiredAdditionalCapacity) { - return HasCapacity(_length + requiredAdditionalCapacity); + return HasCapacity(Length + requiredAdditionalCapacity); } private void AddNullTerminator() { - _buffer[_length] = 0; + Buffer[Length] = 0; } private readonly void ThrowIfBufferLengthIsZero() { - if (_buffer.Length == 0) throw new ArgumentException("Buffer length must be greater than 0."); + if (Buffer.Length == 0) throw new ArgumentException("Buffer length must be greater than 0."); } - private U8StringBuilder AppendFormatInt64(long value, ulong mask, char format, byte precision) + private void AppendFormatInt64(long value, ulong mask, char format, byte precision) { - if (Overflowed) return this; + if (Overflowed) return; // Remove possible sign extension if needed if (mask == 'x' | mask == 'X') @@ -126,7 +122,7 @@ namespace LibHac.Common } // Exclude the null terminator from the buffer because Utf8Formatter doesn't handle it - Span availableBuffer = _buffer.Slice(_length, Capacity - _length); + Span availableBuffer = Buffer.Slice(Length, Capacity - Length); bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten, new StandardFormat(format, precision)); @@ -134,21 +130,19 @@ namespace LibHac.Common if (!bufferLargeEnough) { Overflowed = true; - return this; + return; } - _length += bytesWritten; + Length += bytesWritten; AddNullTerminator(); - - return this; } - private U8StringBuilder AppendFormatUInt64(ulong value, char format, byte precision) + private void AppendFormatUInt64(ulong value, char format, byte precision) { - if (Overflowed) return this; + if (Overflowed) return; // Exclude the null terminator from the buffer because Utf8Formatter doesn't handle it - Span availableBuffer = _buffer.Slice(_length, Capacity - _length); + Span availableBuffer = Buffer.Slice(Length, Capacity - Length); bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten, new StandardFormat(format, precision)); @@ -156,21 +150,19 @@ namespace LibHac.Common if (!bufferLargeEnough) { Overflowed = true; - return this; + return; } - _length += bytesWritten; + Length += bytesWritten; AddNullTerminator(); - - return this; } - private U8StringBuilder AppendFormatFloat(float value, char format, byte precision) + private void AppendFormatFloat(float value, char format, byte precision) { - if (Overflowed) return this; + if (Overflowed) return; // Exclude the null terminator from the buffer because Utf8Formatter doesn't handle it - Span availableBuffer = _buffer.Slice(_length, Capacity - _length); + Span availableBuffer = Buffer.Slice(Length, Capacity - Length); bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten, new StandardFormat(format, precision)); @@ -178,21 +170,19 @@ namespace LibHac.Common if (!bufferLargeEnough) { Overflowed = true; - return this; + return; } - _length += bytesWritten; + Length += bytesWritten; AddNullTerminator(); - - return this; } - private U8StringBuilder AppendFormatDouble(double value, char format, byte precision) + private void AppendFormatDouble(double value, char format, byte precision) { - if (Overflowed) return this; + if (Overflowed) return; // Exclude the null terminator from the buffer because Utf8Formatter doesn't handle it - Span availableBuffer = _buffer.Slice(_length, Capacity - _length); + Span availableBuffer = Buffer.Slice(Length, Capacity - Length); bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten, new StandardFormat(format, precision)); @@ -200,15 +190,98 @@ namespace LibHac.Common if (!bufferLargeEnough) { Overflowed = true; - return this; + return; } - _length += bytesWritten; + Length += bytesWritten; AddNullTerminator(); - - return this; } - public override readonly string ToString() => StringUtils.Utf8ZToString(_buffer); + public override readonly string ToString() => StringUtils.Utf8ZToString(Buffer); + } + + public static class U8StringBuilderExtensions + { + public static ref U8StringBuilder Append(this ref U8StringBuilder sb, ReadOnlySpan value) + { + sb.AppendInternal(value); + return ref sb; + } + + public static ref U8StringBuilder Append(this ref U8StringBuilder sb, byte value) + { + sb.AppendInternal(value); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, byte value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, sbyte value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, ushort value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, short value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, uint value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, int value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, ulong value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, long value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, float value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } + + public static ref U8StringBuilder AppendFormat(this ref U8StringBuilder sb, double value, char format = 'G', + byte precision = 255) + { + sb.AppendFormatInternal(value, format, precision); + return ref sb; + } } } diff --git a/src/LibHac/Fs/Shim/Bis.cs b/src/LibHac/Fs/Shim/Bis.cs index cd152d02..ba4f5ba5 100644 --- a/src/LibHac/Fs/Shim/Bis.cs +++ b/src/LibHac/Fs/Shim/Bis.cs @@ -28,9 +28,10 @@ namespace LibHac.Fs.Shim Debug.Assert(nameBuffer.Length >= requiredNameBufferSize); - // ReSharper disable once RedundantAssignment - int size = new U8StringBuilder(nameBuffer).Append(mountName).Append(StringTraits.DriveSeparator).Length; - Debug.Assert(size == requiredNameBufferSize - 1); + var sb = new U8StringBuilder(nameBuffer); + sb.Append(mountName).Append(StringTraits.DriveSeparator); + + Debug.Assert(sb.Length == requiredNameBufferSize - 1); return Result.Success; } @@ -144,7 +145,8 @@ namespace LibHac.Fs.Shim ? StringTraits.NullTerminator : StringTraits.DirectorySeparator; - Result rc = new U8StringBuilder(sfPath.Str).Append(rootPath).Append(endingSeparator).ToSfPath(); + var sb = new U8StringBuilder(sfPath.Str); + Result rc = sb.Append(rootPath).Append(endingSeparator).ToSfPath(); if (rc.IsFailure()) return rc; } else diff --git a/src/LibHac/Fs/Shim/Host.cs b/src/LibHac/Fs/Shim/Host.cs index 48786e31..e26fae22 100644 --- a/src/LibHac/Fs/Shim/Host.cs +++ b/src/LibHac/Fs/Shim/Host.cs @@ -43,9 +43,10 @@ namespace LibHac.Fs.Shim if (nameBuffer.Length < requiredNameBufferSize) return ResultFs.TooLongPath.Log(); - // ReSharper disable once RedundantAssignment - int size = new U8StringBuilder(nameBuffer).Append(HostRootFileSystemPath).Append(_path.Str).Length; - Debug.Assert(size == requiredNameBufferSize - 1); + var sb = new U8StringBuilder(nameBuffer); + sb.Append(HostRootFileSystemPath).Append(_path.Str); + + Debug.Assert(sb.Length == requiredNameBufferSize - 1); return Result.Success; } diff --git a/src/LibHac/FsSystem/FsPath.cs b/src/LibHac/FsSystem/FsPath.cs index ca71e059..208a2983 100644 --- a/src/LibHac/FsSystem/FsPath.cs +++ b/src/LibHac/FsSystem/FsPath.cs @@ -26,9 +26,10 @@ namespace LibHac.FsSystem { fsPath = new FsPath(); - U8StringBuilder builder = new U8StringBuilder(fsPath.Str).Append(path); + var sb = new U8StringBuilder(fsPath.Str); + bool overflowed = sb.Append(path).Overflowed; - return builder.Overflowed ? ResultFs.TooLongPath.Log() : Result.Success; + return overflowed ? ResultFs.TooLongPath.Log() : Result.Success; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/LibHac/Horizon.cs b/src/LibHac/Horizon.cs index 4457db81..f46ac72f 100644 --- a/src/LibHac/Horizon.cs +++ b/src/LibHac/Horizon.cs @@ -10,14 +10,14 @@ namespace LibHac public class Horizon { internal ITimeSpanGenerator Time { get; } - private FileSystemServer FileSystemServer { get; set; } - private BcatServer BcatServer { get; set; } + public FileSystemServer FileSystemServer { get; private set; } + public BcatServer BcatServer { get; private set; } private readonly object _initLocker = new object(); public Horizon(ITimeSpanGenerator timer) { - Time = timer; + Time = timer ?? new StopWatchTimeSpanGenerator(); } public Result OpenFileSystemProxyService(out IFileSystemProxy service) @@ -60,6 +60,18 @@ namespace LibHac return BcatServer.GetServiceCreator(out service, type); } + public void InitializeBcatServer() + { + if (BcatServer != null) return; + + lock (_initLocker) + { + if (BcatServer != null) return; + + BcatServer = new BcatServer(this); + } + } + public void InitializeFileSystemServer(FileSystemCreators fsCreators, IDeviceOperator deviceOperator) { if (FileSystemServer != null) return;