BCAT fixes. Tweak how U8StringBuilder is used

This commit is contained in:
Alex Barney 2020-04-11 22:18:43 -07:00
parent 6e4372ce58
commit f3452bb314
15 changed files with 200 additions and 109 deletions

View file

@ -32,7 +32,7 @@ namespace LibHac.Bcat
public Result GetServiceCreator(out IServiceCreator serviceCreator, BcatServiceType type) public Result GetServiceCreator(out IServiceCreator serviceCreator, BcatServiceType type)
{ {
if ((uint)type < ServiceTypeCount) if ((uint)type >= ServiceTypeCount)
{ {
serviceCreator = default; serviceCreator = default;
return ResultLibHac.ArgumentOutOfRange.Log(); return ResultLibHac.ArgumentOutOfRange.Log();
@ -87,6 +87,9 @@ namespace LibHac.Bcat
if (!rc.IsSuccess()) if (!rc.IsSuccess())
throw new HorizonResultException(rc, "Abort"); throw new HorizonResultException(rc, "Abort");
fsClient.SetAccessLogTarget(AccessLogTarget.All);
FsClient = fsClient;
return fsClient; return fsClient;
} }
} }

View file

@ -2,7 +2,7 @@
namespace LibHac.Bcat.Detail.Ipc namespace LibHac.Bcat.Detail.Ipc
{ {
public interface IDeliveryCacheDirectoryService public interface IDeliveryCacheDirectoryService : IDisposable
{ {
Result Open(ref DirectoryName name); Result Open(ref DirectoryName name);
Result Read(out int entriesRead, Span<DeliveryCacheDirectoryEntry> entryBuffer); Result Read(out int entriesRead, Span<DeliveryCacheDirectoryEntry> entryBuffer);

View file

@ -2,7 +2,7 @@
namespace LibHac.Bcat.Detail.Ipc namespace LibHac.Bcat.Detail.Ipc
{ {
public interface IDeliveryCacheFileService public interface IDeliveryCacheFileService : IDisposable
{ {
Result Open(ref DirectoryName directoryName, ref FileName fileName); Result Open(ref DirectoryName directoryName, ref FileName fileName);
Result Read(out long bytesRead, long offset, Span<byte> destination); Result Read(out long bytesRead, long offset, Span<byte> destination);

View file

@ -2,7 +2,7 @@
namespace LibHac.Bcat.Detail.Ipc namespace LibHac.Bcat.Detail.Ipc
{ {
public interface IDeliveryCacheStorageService public interface IDeliveryCacheStorageService : IDisposable
{ {
Result CreateFileService(out IDeliveryCacheFileService fileService); Result CreateFileService(out IDeliveryCacheFileService fileService);
Result CreateDirectoryService(out IDeliveryCacheDirectoryService directoryService); Result CreateDirectoryService(out IDeliveryCacheDirectoryService directoryService);

View file

@ -48,8 +48,8 @@ namespace LibHac.Bcat.Detail.Service.Core
// Get the mount name // Get the mount name
var mountName = new MountName(); var mountName = new MountName();
new U8StringBuilder(mountName.Name) var sb = new U8StringBuilder(mountName.Name);
.Append(DeliveryCacheMountNamePrefix) sb.Append(DeliveryCacheMountNamePrefix)
.AppendFormat(index, 'd', 2); .AppendFormat(index, 'd', 2);
// Mount the save if enabled // Mount the save if enabled
@ -89,8 +89,8 @@ namespace LibHac.Bcat.Detail.Service.Core
{ {
var mountName = new MountName(); var mountName = new MountName();
new U8StringBuilder(mountName.Name) var sb = new U8StringBuilder(mountName.Name);
.Append(DeliveryCacheMountNamePrefix) sb.Append(DeliveryCacheMountNamePrefix)
.AppendFormat(index, 'd', 2); .AppendFormat(index, 'd', 2);
// Unmount the entry's savedata // Unmount the entry's savedata
@ -115,8 +115,8 @@ namespace LibHac.Bcat.Detail.Service.Core
var mountName = new MountName(); var mountName = new MountName();
new U8StringBuilder(mountName.Name) var sb = new U8StringBuilder(mountName.Name);
.Append(DeliveryCacheMountNamePrefix) sb.Append(DeliveryCacheMountNamePrefix)
.AppendFormat(index, 'd', 2); .AppendFormat(index, 'd', 2);
if (!DisableStorage) if (!DisableStorage)
@ -215,10 +215,10 @@ namespace LibHac.Bcat.Detail.Service.Core
var sb = new U8StringBuilder(pathBuffer); var sb = new U8StringBuilder(pathBuffer);
AppendMountName(ref sb, applicationId); AppendMountName(ref sb, applicationId);
sb.Append(DirectoriesPath); sb.Append(DirectoriesPath)
sb.Append(DirectorySeparator).Append(directoryName.Bytes); .Append(DirectorySeparator).Append(directoryName.Bytes)
sb.Append(DirectorySeparator).Append(FilesDirectoryName); .Append(DirectorySeparator).Append(FilesDirectoryName)
sb.Append(DirectorySeparator).Append(fileName.Bytes); .Append(DirectorySeparator).Append(fileName.Bytes);
} }
} }
@ -229,9 +229,9 @@ namespace LibHac.Bcat.Detail.Service.Core
var sb = new U8StringBuilder(pathBuffer); var sb = new U8StringBuilder(pathBuffer);
AppendMountName(ref sb, applicationId); AppendMountName(ref sb, applicationId);
sb.Append(DirectoriesPath); sb.Append(DirectoriesPath)
sb.Append(DirectorySeparator).Append(directoryName.Bytes); .Append(DirectorySeparator).Append(directoryName.Bytes)
sb.Append(DirectorySeparator).Append(FilesMetaFileName); .Append(DirectorySeparator).Append(FilesMetaFileName);
} }
} }
@ -252,8 +252,8 @@ namespace LibHac.Bcat.Detail.Service.Core
var sb = new U8StringBuilder(pathBuffer); var sb = new U8StringBuilder(pathBuffer);
AppendMountName(ref sb, applicationId); AppendMountName(ref sb, applicationId);
sb.Append(DirectoriesPath); sb.Append(DirectoriesPath)
sb.Append(DirectorySeparator).Append(directoryName.Bytes); .Append(DirectorySeparator).Append(directoryName.Bytes);
} }
} }

View file

@ -4,11 +4,13 @@ using LibHac.Bcat.Detail.Service.Core;
namespace LibHac.Bcat.Detail.Service namespace LibHac.Bcat.Detail.Service
{ {
internal class DeliveryCacheDirectoryService : IDeliveryCacheDirectoryService, IDisposable internal class DeliveryCacheDirectoryService : IDeliveryCacheDirectoryService
{ {
private BcatServer Server { get; } private BcatServer Server { get; }
private object Locker { get; } = new object(); private object Locker { get; } = new object();
private DeliveryCacheStorageService Parent { get; } private DeliveryCacheStorageService Parent { get; }
// ReSharper disable once UnusedAutoPropertyAccessor.Local
private AccessControl Access { get; } private AccessControl Access { get; }
private ulong ApplicationId { get; } private ulong ApplicationId { get; }
private DirectoryName _name; private DirectoryName _name;

View file

@ -6,11 +6,13 @@ using LibHac.Fs;
namespace LibHac.Bcat.Detail.Service namespace LibHac.Bcat.Detail.Service
{ {
internal class DeliveryCacheFileService : IDeliveryCacheFileService, IDisposable internal class DeliveryCacheFileService : IDeliveryCacheFileService
{ {
private BcatServer Server { get; } private BcatServer Server { get; }
private object Locker { get; } = new object(); private object Locker { get; } = new object();
private DeliveryCacheStorageService Parent { get; } private DeliveryCacheStorageService Parent { get; }
// ReSharper disable once UnusedAutoPropertyAccessor.Local
private AccessControl Access { get; } private AccessControl Access { get; }
private ulong ApplicationId { get; } private ulong ApplicationId { get; }
private FileHandle _handle; private FileHandle _handle;

View file

@ -4,12 +4,12 @@ using LibHac.Bcat.Detail.Ipc;
namespace LibHac.Bcat.Detail.Service namespace LibHac.Bcat.Detail.Service
{ {
internal class DeliveryCacheStorageService : IDeliveryCacheStorageService, IDisposable internal class DeliveryCacheStorageService : IDeliveryCacheStorageService
{ {
private const int MaxOpenCount = 8; private const int MaxOpenCount = 8;
private BcatServer Server { get; } private BcatServer Server { get; }
public object Locker { get; } = new object(); private object Locker { get; } = new object();
private AccessControl Access { get; } private AccessControl Access { get; }
private ulong ApplicationId { get; } private ulong ApplicationId { get; }
private int FileServiceOpenCount { get; set; } private int FileServiceOpenCount { get; set; }

View file

@ -6,6 +6,8 @@ namespace LibHac.Bcat.Detail.Service
internal class ServiceCreator : IServiceCreator internal class ServiceCreator : IServiceCreator
{ {
private BcatServer Server { get; } private BcatServer Server { get; }
// ReSharper disable once UnusedAutoPropertyAccessor.Local
private BcatServiceType ServiceType { get; } private BcatServiceType ServiceType { get; }
private AccessControl AccessControl { get; } private AccessControl AccessControl { get; }
@ -35,16 +37,9 @@ namespace LibHac.Bcat.Detail.Service
Result rc = Server.GetStorageManager().Open(applicationId.Value); Result rc = Server.GetStorageManager().Open(applicationId.Value);
if (rc.IsFailure()) return rc; 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); service = new DeliveryCacheStorageService(Server, applicationId.Value, AccessControl);
}
finally
{
Server.GetStorageManager().Release(applicationId.Value);
}
return Result.Success; return Result.Success;
} }

View file

@ -171,7 +171,7 @@ namespace LibHac.Common
public static bool IsAlpha(byte c) 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) public static bool IsDigit(byte c)

View file

@ -10,18 +10,15 @@ namespace LibHac.Common
{ {
private const int NullTerminatorLength = 1; private const int NullTerminatorLength = 1;
private readonly Span<byte> _buffer; public Span<byte> Buffer { get; }
private int _length; public int Length { get; private set; }
public bool Overflowed { get; private set; } public bool Overflowed { get; private set; }
public readonly int Length => _length; public readonly int Capacity => Buffer.Length - NullTerminatorLength;
public readonly int Capacity => _buffer.Length - NullTerminatorLength;
public readonly Span<byte> Buffer => _buffer;
public U8StringBuilder(Span<byte> buffer) public U8StringBuilder(Span<byte> buffer)
{ {
_buffer = buffer; Buffer = buffer;
_length = 0; Length = 0;
Overflowed = false; Overflowed = false;
ThrowIfBufferLengthIsZero(); ThrowIfBufferLengthIsZero();
@ -29,70 +26,69 @@ namespace LibHac.Common
AddNullTerminator(); AddNullTerminator();
} }
public U8StringBuilder Append(ReadOnlySpan<byte> 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<byte> value)
{ {
if (Overflowed) return this; if (Overflowed) return;
int valueLength = StringUtils.GetLength(value); int valueLength = StringUtils.GetLength(value);
if (!HasAdditionalCapacity(valueLength)) if (!HasAdditionalCapacity(valueLength))
{ {
Overflowed = true; Overflowed = true;
return this; return;
} }
value.Slice(0, valueLength).CopyTo(_buffer.Slice(_length)); value.Slice(0, valueLength).CopyTo(Buffer.Slice(Length));
_length += valueLength; Length += valueLength;
AddNullTerminator(); AddNullTerminator();
return this;
} }
public U8StringBuilder Append(byte value) internal void AppendInternal(byte value)
{ {
if (Overflowed) return this; if (Overflowed) return;
if (!HasAdditionalCapacity(1)) if (!HasAdditionalCapacity(1))
{ {
Overflowed = true; Overflowed = true;
return this; return;
} }
_buffer[_length] = value; Buffer[Length] = value;
_length++; Length++;
AddNullTerminator(); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); AppendFormatDouble(value, format, precision);
private readonly bool HasCapacity(int requiredCapacity) private readonly bool HasCapacity(int requiredCapacity)
@ -102,22 +98,22 @@ namespace LibHac.Common
private readonly bool HasAdditionalCapacity(int requiredAdditionalCapacity) private readonly bool HasAdditionalCapacity(int requiredAdditionalCapacity)
{ {
return HasCapacity(_length + requiredAdditionalCapacity); return HasCapacity(Length + requiredAdditionalCapacity);
} }
private void AddNullTerminator() private void AddNullTerminator()
{ {
_buffer[_length] = 0; Buffer[Length] = 0;
} }
private readonly void ThrowIfBufferLengthIsZero() 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 // Remove possible sign extension if needed
if (mask == 'x' | mask == 'X') 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 // Exclude the null terminator from the buffer because Utf8Formatter doesn't handle it
Span<byte> availableBuffer = _buffer.Slice(_length, Capacity - _length); Span<byte> availableBuffer = Buffer.Slice(Length, Capacity - Length);
bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten, bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten,
new StandardFormat(format, precision)); new StandardFormat(format, precision));
@ -134,21 +130,19 @@ namespace LibHac.Common
if (!bufferLargeEnough) if (!bufferLargeEnough)
{ {
Overflowed = true; Overflowed = true;
return this; return;
} }
_length += bytesWritten; Length += bytesWritten;
AddNullTerminator(); 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 // Exclude the null terminator from the buffer because Utf8Formatter doesn't handle it
Span<byte> availableBuffer = _buffer.Slice(_length, Capacity - _length); Span<byte> availableBuffer = Buffer.Slice(Length, Capacity - Length);
bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten, bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten,
new StandardFormat(format, precision)); new StandardFormat(format, precision));
@ -156,21 +150,19 @@ namespace LibHac.Common
if (!bufferLargeEnough) if (!bufferLargeEnough)
{ {
Overflowed = true; Overflowed = true;
return this; return;
} }
_length += bytesWritten; Length += bytesWritten;
AddNullTerminator(); 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 // Exclude the null terminator from the buffer because Utf8Formatter doesn't handle it
Span<byte> availableBuffer = _buffer.Slice(_length, Capacity - _length); Span<byte> availableBuffer = Buffer.Slice(Length, Capacity - Length);
bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten, bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten,
new StandardFormat(format, precision)); new StandardFormat(format, precision));
@ -178,21 +170,19 @@ namespace LibHac.Common
if (!bufferLargeEnough) if (!bufferLargeEnough)
{ {
Overflowed = true; Overflowed = true;
return this; return;
} }
_length += bytesWritten; Length += bytesWritten;
AddNullTerminator(); 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 // Exclude the null terminator from the buffer because Utf8Formatter doesn't handle it
Span<byte> availableBuffer = _buffer.Slice(_length, Capacity - _length); Span<byte> availableBuffer = Buffer.Slice(Length, Capacity - Length);
bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten, bool bufferLargeEnough = Utf8Formatter.TryFormat(value, availableBuffer, out int bytesWritten,
new StandardFormat(format, precision)); new StandardFormat(format, precision));
@ -200,15 +190,98 @@ namespace LibHac.Common
if (!bufferLargeEnough) if (!bufferLargeEnough)
{ {
Overflowed = true; Overflowed = true;
return this; return;
} }
_length += bytesWritten; Length += bytesWritten;
AddNullTerminator(); 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<byte> 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;
}
} }
} }

View file

@ -28,9 +28,10 @@ namespace LibHac.Fs.Shim
Debug.Assert(nameBuffer.Length >= requiredNameBufferSize); Debug.Assert(nameBuffer.Length >= requiredNameBufferSize);
// ReSharper disable once RedundantAssignment var sb = new U8StringBuilder(nameBuffer);
int size = new U8StringBuilder(nameBuffer).Append(mountName).Append(StringTraits.DriveSeparator).Length; sb.Append(mountName).Append(StringTraits.DriveSeparator);
Debug.Assert(size == requiredNameBufferSize - 1);
Debug.Assert(sb.Length == requiredNameBufferSize - 1);
return Result.Success; return Result.Success;
} }
@ -144,7 +145,8 @@ namespace LibHac.Fs.Shim
? StringTraits.NullTerminator ? StringTraits.NullTerminator
: StringTraits.DirectorySeparator; : 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; if (rc.IsFailure()) return rc;
} }
else else

View file

@ -43,9 +43,10 @@ namespace LibHac.Fs.Shim
if (nameBuffer.Length < requiredNameBufferSize) if (nameBuffer.Length < requiredNameBufferSize)
return ResultFs.TooLongPath.Log(); return ResultFs.TooLongPath.Log();
// ReSharper disable once RedundantAssignment var sb = new U8StringBuilder(nameBuffer);
int size = new U8StringBuilder(nameBuffer).Append(HostRootFileSystemPath).Append(_path.Str).Length; sb.Append(HostRootFileSystemPath).Append(_path.Str);
Debug.Assert(size == requiredNameBufferSize - 1);
Debug.Assert(sb.Length == requiredNameBufferSize - 1);
return Result.Success; return Result.Success;
} }

View file

@ -26,9 +26,10 @@ namespace LibHac.FsSystem
{ {
fsPath = new FsPath(); 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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View file

@ -10,14 +10,14 @@ namespace LibHac
public class Horizon public class Horizon
{ {
internal ITimeSpanGenerator Time { get; } internal ITimeSpanGenerator Time { get; }
private FileSystemServer FileSystemServer { get; set; } public FileSystemServer FileSystemServer { get; private set; }
private BcatServer BcatServer { get; set; } public BcatServer BcatServer { get; private set; }
private readonly object _initLocker = new object(); private readonly object _initLocker = new object();
public Horizon(ITimeSpanGenerator timer) public Horizon(ITimeSpanGenerator timer)
{ {
Time = timer; Time = timer ?? new StopWatchTimeSpanGenerator();
} }
public Result OpenFileSystemProxyService(out IFileSystemProxy service) public Result OpenFileSystemProxyService(out IFileSystemProxy service)
@ -60,6 +60,18 @@ namespace LibHac
return BcatServer.GetServiceCreator(out service, type); 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) public void InitializeFileSystemServer(FileSystemCreators fsCreators, IDeviceOperator deviceOperator)
{ {
if (FileSystemServer != null) return; if (FileSystemServer != null) return;