Add BCAT storage skeleton

This commit is contained in:
Alex Barney 2020-04-07 00:22:12 -07:00
parent 5018bbad6a
commit da78e7e8ce
23 changed files with 553 additions and 8 deletions

View file

@ -3,4 +3,5 @@ Fs,2
Loader,9
Kvdb,20
Sdmmc,24
Bcat,122
LibHac,428
1 Name Index
3 Loader 9
4 Kvdb 20
5 Sdmmc 24
6 Bcat 122
7 LibHac 428

View file

@ -3,4 +3,5 @@ Fs,LibHac.Fs,LibHac/Fs/ResultFs.cs
Loader,LibHac.Loader,LibHac/Loader/ResultLoader.cs
Kvdb,LibHac.Kvdb,LibHac/Kvdb/ResultKvdb.cs
Sdmmc,LibHac.FsService,LibHac/FsService/ResultSdmmc.cs
Bcat,LibHac.Bcat,LibHac/Bcat/ResultBcat.cs
LibHac,LibHac.Common,LibHac/Common/ResultLibHac.cs
1 Name Namespace Path
3 Loader LibHac.Loader LibHac/Loader/ResultLoader.cs
4 Kvdb LibHac.Kvdb LibHac/Kvdb/ResultKvdb.cs
5 Sdmmc LibHac.FsService LibHac/FsService/ResultSdmmc.cs
6 Bcat LibHac.Bcat LibHac/Bcat/ResultBcat.cs
7 LibHac LibHac.Common LibHac/Common/ResultLibHac.cs

View file

@ -277,6 +277,19 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
24,1,,DeviceNotFound,
24,4,,DeviceAsleep,
122,1,,InvalidArgument,
122,2,,NotFound,
122,7,,NotOpen,
122,9,,ServiceOpenLimitReached,
122,10,,SaveDataNotFount,
122,31,,NetworkServiceAccountNotAvailable,
122,90,,PermissionDenied,
122,204,,InvalidStorageMetaVersion,
122,205,,StorageOpenLimitReached,
123,0,4999,SslService,
124,0,,Cancelled,
@ -307,6 +320,8 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
428,3,,ArgumentOutOfRange,
428,4,,BufferTooSmall,
428,51,,ServiceNotInitialized,
428,1000,1999,InvalidData,
428,1001,1019,InvalidKip,
428,1002,,InvalidKipFileSize,The size of the KIP file was smaller than expected.

1 Module,DescriptionStart,DescriptionEnd,Name,Summary
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
320
321
322
323
324
325
326
327

View file

@ -0,0 +1,93 @@
using System.Diagnostics;
using LibHac.Bcat.Detail.Ipc;
using LibHac.Bcat.Detail.Service;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.Bcat
{
public class BcatServer
{
private const int ServiceTypeCount = 4;
private Horizon ServiceManager { get; }
private ServiceCreator[] ServiceCreators { get; } = new ServiceCreator[ServiceTypeCount];
private readonly object _storageManagerInitLocker = new object();
private readonly object _fsInitLocker = new object();
private DeliveryCacheStorageManager StorageManager { get; set; }
private FileSystemClient FsClient { get; set; }
public BcatServer(Horizon horizon)
{
ServiceManager = horizon;
InitServiceCreator(BcatServiceType.BcatU, AccessControl.Bit1);
InitServiceCreator(BcatServiceType.BcatS, AccessControl.Bit2);
InitServiceCreator(BcatServiceType.BcatM, AccessControl.Bit2 | AccessControl.Bit3);
InitServiceCreator(BcatServiceType.BcatA, AccessControl.All);
}
public Result GetServiceCreator(out IServiceCreator serviceCreator, BcatServiceType type)
{
if ((uint)type < ServiceTypeCount)
{
serviceCreator = default;
return ResultLibHac.ArgumentOutOfRange.Log();
}
serviceCreator = ServiceCreators[(int)type];
return Result.Success;
}
private void InitServiceCreator(BcatServiceType type, AccessControl accessControl)
{
Debug.Assert((uint)type < ServiceTypeCount);
ServiceCreators[(int)type] = new ServiceCreator(this, type, accessControl);
}
internal DeliveryCacheStorageManager GetStorageManager()
{
return StorageManager ?? InitStorageManager();
}
internal FileSystemClient GetFsClient()
{
return FsClient ?? InitFsClient();
}
private DeliveryCacheStorageManager InitStorageManager()
{
lock (_storageManagerInitLocker)
{
if (StorageManager != null)
{
return StorageManager;
}
StorageManager = new DeliveryCacheStorageManager();
return StorageManager;
}
}
private FileSystemClient InitFsClient()
{
lock (_fsInitLocker)
{
if (FsClient != null)
{
return FsClient;
}
Result rc = ServiceManager.OpenFileSystemClient(out FileSystemClient fsClient);
if (!rc.IsSuccess())
throw new HorizonResultException(rc, "Abort");
return fsClient;
}
}
}
}

View file

@ -0,0 +1,10 @@
namespace LibHac.Bcat
{
public enum BcatServiceType
{
BcatU,
BcatS,
BcatM,
BcatA
}
}

View file

@ -0,0 +1,12 @@
using System.Runtime.InteropServices;
namespace LibHac.Bcat
{
[StructLayout(LayoutKind.Explicit, Size = 0x38)]
public struct DeliveryCacheDirectoryEntry
{
[FieldOffset(0x00)] public FileName Name;
[FieldOffset(0x20)] public long Size;
[FieldOffset(0x28)] public Digest Digest;
}
}

View file

@ -0,0 +1,11 @@
using System;
namespace LibHac.Bcat.Detail.Ipc
{
public interface IDeliveryCacheDirectoryService
{
Result Open(ref DirectoryName name);
Result Read(ref int entriesRead, Span<DeliveryCacheDirectoryEntry> entryBuffer);
Result GetCount(ref int count);
}
}

View file

@ -0,0 +1,12 @@
using System;
namespace LibHac.Bcat.Detail.Ipc
{
public interface IDeliveryCacheFileService
{
Result Open(ref DirectoryName directoryName, ref FileName fileName);
Result Read(out long bytesRead, long offset, Span<byte> destination);
Result GetSize(out long size);
Result GetDigest(out Digest digest);
}
}

View file

@ -0,0 +1,11 @@
using System;
namespace LibHac.Bcat.Detail.Ipc
{
public interface IDeliveryCacheStorageService
{
Result CreateFileService(out IDeliveryCacheFileService fileService);
Result CreateDirectoryService(out IDeliveryCacheDirectoryService directoryService);
Result EnumerateDeliveryCacheDirectory(out int namesRead, Span<DirectoryName> nameBuffer);
}
}

View file

@ -0,0 +1,10 @@
using LibHac.Ncm;
namespace LibHac.Bcat.Detail.Ipc
{
public interface IServiceCreator
{
Result CreateDeliveryCacheStorageServiceWithApplicationId(out IDeliveryCacheStorageService service,
TitleId applicationId);
}
}

View file

@ -0,0 +1,16 @@
using System;
namespace LibHac.Bcat.Detail.Service
{
[Flags]
internal enum AccessControl
{
None = 0,
Bit0 = 1 << 0,
Bit1 = 1 << 1,
Bit2 = 1 << 2,
Bit3 = 1 << 3,
Bit4 = 1 << 4,
All = ~0
}
}

View file

@ -0,0 +1,39 @@
using System;
using LibHac.Bcat.Detail.Ipc;
namespace LibHac.Bcat.Detail.Service
{
internal class DeliveryCacheDirectoryService : IDeliveryCacheDirectoryService
{
public object Locker { get; } = new object();
private DeliveryCacheStorageService Parent { get; }
private AccessControl Access { get; }
private ulong ApplicationId { get; }
private DirectoryName _name;
private bool IsDirectoryOpen { get; set; }
private int Count { get; set; }
public DeliveryCacheDirectoryService(DeliveryCacheStorageService parent, ulong applicationId,
AccessControl accessControl)
{
Parent = parent;
ApplicationId = applicationId;
Access = accessControl;
}
public Result Open(ref DirectoryName name)
{
throw new NotImplementedException();
}
public Result Read(ref int entriesRead, Span<DeliveryCacheDirectoryEntry> entryBuffer)
{
throw new NotImplementedException();
}
public Result GetCount(ref int count)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,12 @@
using System.Runtime.InteropServices;
namespace LibHac.Bcat.Detail.Service
{
[StructLayout(LayoutKind.Explicit, Size = 0x80)]
internal struct DeliveryCacheFileEntryMeta
{
[FieldOffset(0x00)] public FileName Name;
[FieldOffset(0x20)] public long Size;
[FieldOffset(0x30)] public Digest Digest;
}
}

View file

@ -0,0 +1,45 @@
using System;
using LibHac.Bcat.Detail.Ipc;
using LibHac.Fs;
namespace LibHac.Bcat.Detail.Service
{
internal class DeliveryCacheFileService : IDeliveryCacheFileService
{
public object Locker { get; } = new object();
private DeliveryCacheStorageService Parent { get; }
private AccessControl Access { get; }
private ulong ApplicationId { get; }
private FileHandle Handle { get; set; }
private DeliveryCacheFileEntryMeta _metaEntry;
private bool IsFileOpen { get; set; }
public DeliveryCacheFileService(DeliveryCacheStorageService parent, ulong applicationId,
AccessControl accessControl)
{
Parent = parent;
ApplicationId = applicationId;
Access = accessControl;
}
public Result Open(ref DirectoryName directoryName, ref FileName fileName)
{
throw new NotImplementedException();
}
public Result Read(out long bytesRead, long offset, Span<byte> destination)
{
throw new NotImplementedException();
}
public Result GetSize(out long size)
{
throw new NotImplementedException();
}
public Result GetDigest(out Digest digest)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,17 @@
namespace LibHac.Bcat.Detail.Service
{
internal class DeliveryCacheStorageManager
{
private const int MaxEntryCount = 4;
private readonly object _locker = new object();
private Entry[] Entries { get; set; } = new Entry[MaxEntryCount];
private bool UseRealStorage { get; set; }
private struct Entry
{
public ulong ApplicationId { get; set; }
public long RefCount { get; set; }
}
}
}

View file

@ -0,0 +1,35 @@
using System;
using LibHac.Bcat.Detail.Ipc;
namespace LibHac.Bcat.Detail.Service
{
internal class DeliveryCacheStorageService : IDeliveryCacheStorageService
{
public object Locker { get; } = new object();
private AccessControl Access { get; }
private ulong ApplicationId { get; }
private int OpenFileServiceCount { get; set; }
private int OpenDirectoryServiceCount { get; set; }
public DeliveryCacheStorageService(ulong applicationId, AccessControl accessControl)
{
ApplicationId = applicationId;
Access = accessControl;
}
public Result CreateFileService(out IDeliveryCacheFileService fileService)
{
throw new NotImplementedException();
}
public Result CreateDirectoryService(out IDeliveryCacheDirectoryService directoryService)
{
throw new NotImplementedException();
}
public Result EnumerateDeliveryCacheDirectory(out int namesRead, Span<DirectoryName> nameBuffer)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,37 @@
using System;
using LibHac.Bcat.Detail.Ipc;
using LibHac.Ncm;
namespace LibHac.Bcat.Detail.Service
{
internal class ServiceCreator : IServiceCreator
{
private BcatServer Parent { get; }
private BcatServiceType ServiceType { get; }
private AccessControl AccessControl { get; }
public ServiceCreator(BcatServer parentServer, BcatServiceType type, AccessControl accessControl)
{
Parent = parentServer;
ServiceType = type;
AccessControl = accessControl;
}
public Result CreateDeliveryCacheStorageServiceWithApplicationId(out IDeliveryCacheStorageService service,
TitleId applicationId)
{
service = default;
if (!AccessControl.HasFlag(AccessControl.Bit2))
return ResultBcat.PermissionDenied.Log();
return CreateDeliveryCacheStorageServiceImpl(out service, applicationId);
}
private Result CreateDeliveryCacheStorageServiceImpl(out IDeliveryCacheStorageService service,
TitleId applicationId)
{
throw new NotImplementedException();
}
}
}

28
src/LibHac/Bcat/Digest.cs Normal file
View file

@ -0,0 +1,28 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using LibHac.Common;
namespace LibHac.Bcat
{
[DebuggerDisplay("{ToString()}")]
[StructLayout(LayoutKind.Sequential, Size = 16)]
public struct Digest
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1;
public byte this[int i]
{
get => Bytes[i];
set => Bytes[i] = value;
}
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
public override string ToString()
{
return Bytes.ToHexString();
}
}
}

View file

@ -0,0 +1,30 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using LibHac.Common;
namespace LibHac.Bcat
{
[DebuggerDisplay("{ToString()}")]
[StructLayout(LayoutKind.Sequential, Size = 32)]
public struct DirectoryName
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy2;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy3;
public byte this[int i]
{
get => Bytes[i];
set => Bytes[i] = value;
}
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
public override string ToString()
{
return StringUtils.Utf8ZToString(Bytes);
}
}
}

View file

@ -0,0 +1,30 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using LibHac.Common;
namespace LibHac.Bcat
{
[DebuggerDisplay("{ToString()}")]
[StructLayout(LayoutKind.Sequential, Size = 32)]
public struct FileName
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy2;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy3;
public byte this[int i]
{
get => Bytes[i];
set => Bytes[i] = value;
}
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
public override string ToString()
{
return StringUtils.Utf8ZToString(Bytes);
}
}
}

View file

@ -0,0 +1,37 @@
//-----------------------------------------------------------------------------
// This file was automatically generated.
// Changes to this file will be lost when the file is regenerated.
//
// To change this file, modify /build/CodeGen/results.csv at the root of this
// repo and run the build script.
//
// The script can be run with the "codegen" option to run only the
// code generation portion of the build.
//-----------------------------------------------------------------------------
namespace LibHac.Bcat
{
public static class ResultBcat
{
public const int ModuleBcat = 122;
/// <summary>Error code: 2122-0001; Inner value: 0x27a</summary>
public static Result.Base InvalidArgument => new Result.Base(ModuleBcat, 1);
/// <summary>Error code: 2122-0002; Inner value: 0x47a</summary>
public static Result.Base NotFound => new Result.Base(ModuleBcat, 2);
/// <summary>Error code: 2122-0007; Inner value: 0xe7a</summary>
public static Result.Base NotOpen => new Result.Base(ModuleBcat, 7);
/// <summary>Error code: 2122-0009; Inner value: 0x127a</summary>
public static Result.Base ServiceOpenLimitReached => new Result.Base(ModuleBcat, 9);
/// <summary>Error code: 2122-0010; Inner value: 0x147a</summary>
public static Result.Base SaveDataNotFount => new Result.Base(ModuleBcat, 10);
/// <summary>Error code: 2122-0031; Inner value: 0x3e7a</summary>
public static Result.Base NetworkServiceAccountNotAvailable => new Result.Base(ModuleBcat, 31);
/// <summary>Error code: 2122-0090; Inner value: 0xb47a</summary>
public static Result.Base PermissionDenied => new Result.Base(ModuleBcat, 90);
/// <summary>Error code: 2122-0204; Inner value: 0x1987a</summary>
public static Result.Base InvalidStorageMetaVersion => new Result.Base(ModuleBcat, 204);
/// <summary>Error code: 2122-0205; Inner value: 0x19a7a</summary>
public static Result.Base StorageOpenLimitReached => new Result.Base(ModuleBcat, 205);
}
}

View file

@ -26,6 +26,9 @@ namespace LibHac.Common
/// <summary>Error code: 2428-0004; Inner value: 0x9ac</summary>
public static Result.Base BufferTooSmall => new Result.Base(ModuleLibHac, 4);
/// <summary>Error code: 2428-0051; Inner value: 0x67ac</summary>
public static Result.Base ServiceNotInitialized => new Result.Base(ModuleLibHac, 51);
/// <summary>Error code: 2428-1000; Range: 1000-1999; Inner value: 0x7d1ac</summary>
public static Result.Base InvalidData { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleLibHac, 1000, 1999); }
/// <summary>Error code: 2428-1001; Range: 1001-1019; Inner value: 0x7d3ac</summary>

View file

@ -1,4 +1,7 @@
using LibHac.Fs;
using LibHac.Bcat;
using LibHac.Bcat.Detail.Ipc;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsService;
using LibHac.FsService.Creators;
@ -7,32 +10,69 @@ namespace LibHac
public class Horizon
{
internal ITimeSpanGenerator Time { get; }
public FileSystemClient Fs { get; }
public FileSystemServer FsSrv { get; private set; }
private FileSystemServer FileSystemServer { get; set; }
private BcatServer BcatServer { get; set; }
private readonly object _initLocker = new object();
public Horizon(ITimeSpanGenerator timer)
{
Time = timer;
}
Fs = new FileSystemClient(timer);
public Result OpenFileSystemProxyService(out IFileSystemProxy service)
{
if (FileSystemServer is null)
{
service = default;
return ResultLibHac.ServiceNotInitialized.Log();
}
service = FileSystemServer.CreateFileSystemProxyService();
return Result.Success;
}
public Result OpenFileSystemClient(out FileSystemClient client)
{
if (FileSystemServer is null)
{
client = default;
return ResultLibHac.ServiceNotInitialized.Log();
}
client = FileSystemServer.CreateFileSystemClient();
return Result.Success;
}
public Result OpenBcatUService(out IServiceCreator service) => OpenBcatService(out service, BcatServiceType.BcatU);
public Result OpenBcatSService(out IServiceCreator service) => OpenBcatService(out service, BcatServiceType.BcatS);
public Result OpenBcatMService(out IServiceCreator service) => OpenBcatService(out service, BcatServiceType.BcatM);
public Result OpenBcatAService(out IServiceCreator service) => OpenBcatService(out service, BcatServiceType.BcatA);
private Result OpenBcatService(out IServiceCreator service, BcatServiceType type)
{
if (BcatServer is null)
{
service = default;
return ResultLibHac.ServiceNotInitialized.Log();
}
return BcatServer.GetServiceCreator(out service, type);
}
public void InitializeFileSystemServer(FileSystemCreators fsCreators, IDeviceOperator deviceOperator)
{
if (FsSrv != null) return;
if (FileSystemServer != null) return;
lock (_initLocker)
{
if (FsSrv != null) return;
if (FileSystemServer != null) return;
var config = new FileSystemServerConfig();
config.FsCreators = fsCreators;
config.DeviceOperator = deviceOperator;
FsSrv = new FileSystemServer(config);
FileSystemServer = new FileSystemServer(config);
}
}
}