Add EnumerateDeliveryCacheDirectory

This commit is contained in:
Alex Barney 2020-04-30 13:58:20 -07:00
parent 1974adb33e
commit 32405fee5f
3 changed files with 140 additions and 2 deletions

View file

@ -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<byte> 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<byte> buffer = MemoryMarshal.Cast<DeliveryCacheDirectoryMetaEntry, byte>(Entries);
rc = fs.ReadFile(out bytesRead, handle, 4, buffer);
if (rc.IsFailure()) return rc;
Count = (int)((uint)bytesRead / Unsafe.SizeOf<DeliveryCacheDirectoryMetaEntry>());
return Result.Success;
}
finally
{
fs.CloseFile(handle);
}
}
}
}
}

View file

@ -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;
}
}

View file

@ -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 @@ namespace LibHac.Bcat.Detail.Service
return Result.Success;
}
}
public Result CreateDirectoryService(out IDeliveryCacheDirectoryService service)
{
lock (Locker)
@ -56,7 +58,33 @@ namespace LibHac.Bcat.Detail.Service
public Result EnumerateDeliveryCacheDirectory(out int namesRead, Span<DirectoryName> 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()