From 32405fee5f20c511ef9f76fc8bb0e45267c3f3a1 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Thu, 30 Apr 2020 13:58:20 -0700 Subject: [PATCH] Add EnumerateDeliveryCacheDirectory --- .../DeliveryCacheDirectoryMetaAccessor.cs | 99 +++++++++++++++++++ .../Core/DeliveryCacheDirectoryMetaEntry.cs | 11 +++ .../Service/DeliveryCacheStorageService.cs | 32 +++++- 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheDirectoryMetaAccessor.cs create mode 100644 src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheDirectoryMetaEntry.cs diff --git a/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheDirectoryMetaAccessor.cs b/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheDirectoryMetaAccessor.cs new file mode 100644 index 00000000..5d2ea757 --- /dev/null +++ b/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheDirectoryMetaAccessor.cs @@ -0,0 +1,99 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using LibHac.Common; +using LibHac.Fs; + +namespace LibHac.Bcat.Detail.Service.Core +{ + internal class DeliveryCacheDirectoryMetaAccessor + { + private const int MaxEntryCount = 100; + private const int MetaFileHeaderValue = 1; + + private BcatServer Server { get; } + private object Locker { get; } = new object(); + private DeliveryCacheDirectoryMetaEntry[] Entries { get; } = new DeliveryCacheDirectoryMetaEntry[MaxEntryCount]; + public int Count { get; private set; } + + public DeliveryCacheDirectoryMetaAccessor(BcatServer server) + { + Server = server; + } + + public Result ReadApplicationDirectoryMeta(ulong applicationId, bool allowMissingMetaFile) + { + Span metaPath = stackalloc byte[0x50]; + Server.GetStorageManager().GetDirectoriesMetaPath(metaPath, applicationId); + + return Read(new U8Span(metaPath), allowMissingMetaFile); + } + + public Result GetEntry(out DeliveryCacheDirectoryMetaEntry entry, int index) + { + lock (Locker) + { + if (index >= Count) + { + entry = default; + return ResultBcat.NotFound.Log(); + } + + entry = Entries[index]; + return Result.Success; + } + } + + private Result Read(U8Span path, bool allowMissingMetaFile) + { + lock (Locker) + { + FileSystemClient fs = Server.GetFsClient(); + + Result rc = fs.OpenFile(out FileHandle handle, path, OpenMode.Read); + + if (rc.IsFailure()) + { + if (ResultFs.PathNotFound.Includes(rc)) + { + if (allowMissingMetaFile) + { + Count = 0; + return Result.Success; + } + + return ResultBcat.NotFound.LogConverted(rc); + } + + return rc; + } + + try + { + Count = 0; + int header = 0; + + // Verify the header value + rc = fs.ReadFile(out long bytesRead, handle, 0, SpanHelpers.AsByteSpan(ref header)); + if (rc.IsFailure()) return rc; + + if (bytesRead != sizeof(int) || header != MetaFileHeaderValue) + return ResultBcat.InvalidDeliveryCacheStorageFile.Log(); + + // Read all the directory entries + Span buffer = MemoryMarshal.Cast(Entries); + rc = fs.ReadFile(out bytesRead, handle, 4, buffer); + if (rc.IsFailure()) return rc; + + Count = (int)((uint)bytesRead / Unsafe.SizeOf()); + + return Result.Success; + } + finally + { + fs.CloseFile(handle); + } + } + } + } +} diff --git a/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheDirectoryMetaEntry.cs b/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheDirectoryMetaEntry.cs new file mode 100644 index 00000000..116fb698 --- /dev/null +++ b/src/LibHac/Bcat/Detail/Service/Core/DeliveryCacheDirectoryMetaEntry.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace LibHac.Bcat.Detail.Service.Core +{ + [StructLayout(LayoutKind.Explicit, Size = 0x40)] + internal struct DeliveryCacheDirectoryMetaEntry + { + [FieldOffset(0x00)] public DirectoryName Name; + [FieldOffset(0x20)] public Digest Digest; + } +} diff --git a/src/LibHac/Bcat/Detail/Service/DeliveryCacheStorageService.cs b/src/LibHac/Bcat/Detail/Service/DeliveryCacheStorageService.cs index 2ee0d976..27699454 100644 --- a/src/LibHac/Bcat/Detail/Service/DeliveryCacheStorageService.cs +++ b/src/LibHac/Bcat/Detail/Service/DeliveryCacheStorageService.cs @@ -1,6 +1,8 @@ using System; using System.Diagnostics; using LibHac.Bcat.Detail.Ipc; +using LibHac.Bcat.Detail.Service.Core; +using LibHac.Common; namespace LibHac.Bcat.Detail.Service { @@ -37,7 +39,7 @@ public Result CreateFileService(out IDeliveryCacheFileService service) return Result.Success; } } - + public Result CreateDirectoryService(out IDeliveryCacheDirectoryService service) { lock (Locker) @@ -56,7 +58,33 @@ public Result CreateDirectoryService(out IDeliveryCacheDirectoryService service) public Result EnumerateDeliveryCacheDirectory(out int namesRead, Span nameBuffer) { - throw new NotImplementedException(); + lock (Locker) + { + namesRead = default; + + var metaReader = new DeliveryCacheDirectoryMetaAccessor(Server); + Result rc = metaReader.ReadApplicationDirectoryMeta(ApplicationId, true); + if (rc.IsFailure()) return rc; + + int i; + for (i = 0; i < nameBuffer.Length; i++) + { + rc = metaReader.GetEntry(out DeliveryCacheDirectoryMetaEntry entry, i); + + if (rc.IsFailure()) + { + if (!ResultBcat.NotFound.Includes(rc)) + return rc; + + break; + } + + StringUtils.Copy(nameBuffer[i].Bytes, entry.Name.Bytes); + } + + namesRead = i; + return Result.Success; + } } internal void NotifyCloseFile()