mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add the logger from nn::diag
This commit is contained in:
parent
7950a91dd0
commit
39977d8e90
13 changed files with 434 additions and 15 deletions
38
src/LibHac/Diag/DiagClient.cs
Normal file
38
src/LibHac/Diag/DiagClient.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
namespace LibHac.Diag
|
||||||
|
{
|
||||||
|
public class DiagClient
|
||||||
|
{
|
||||||
|
internal DiagClientGlobals Globals;
|
||||||
|
|
||||||
|
public DiagClientImpl Impl => new DiagClientImpl(this);
|
||||||
|
internal HorizonClient Hos => Globals.Hos;
|
||||||
|
|
||||||
|
public DiagClient(HorizonClient horizonClient)
|
||||||
|
{
|
||||||
|
Globals.Initialize(this, horizonClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal struct DiagClientGlobals
|
||||||
|
{
|
||||||
|
public HorizonClient Hos;
|
||||||
|
public object InitMutex;
|
||||||
|
public LogObserverGlobals LogObserver;
|
||||||
|
|
||||||
|
public void Initialize(DiagClient diagClient, HorizonClient horizonClient)
|
||||||
|
{
|
||||||
|
Hos = horizonClient;
|
||||||
|
InitMutex = new object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions in the nn::diag::detail namespace use this struct.
|
||||||
|
public readonly struct DiagClientImpl
|
||||||
|
{
|
||||||
|
internal readonly DiagClient Diag;
|
||||||
|
internal HorizonClient Hos => Diag.Hos;
|
||||||
|
internal ref DiagClientGlobals Globals => ref Diag.Globals;
|
||||||
|
|
||||||
|
internal DiagClientImpl(DiagClient parentClient) => Diag = parentClient;
|
||||||
|
}
|
||||||
|
}
|
145
src/LibHac/Diag/Impl/ObserverManager.cs
Normal file
145
src/LibHac/Diag/Impl/ObserverManager.cs
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LibHac.Os;
|
||||||
|
|
||||||
|
namespace LibHac.Diag.Impl
|
||||||
|
{
|
||||||
|
internal interface IObserverHolder
|
||||||
|
{
|
||||||
|
bool IsRegistered { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ObserverManager<TObserver, TItem> where TObserver : IObserverHolder
|
||||||
|
{
|
||||||
|
private LinkedList<TObserver> _observers;
|
||||||
|
private ReaderWriterLock _rwLock;
|
||||||
|
|
||||||
|
public delegate void Function(ref TObserver observer, in TItem item);
|
||||||
|
|
||||||
|
public ObserverManager(HorizonClient hos)
|
||||||
|
{
|
||||||
|
_observers = new LinkedList<TObserver>();
|
||||||
|
_rwLock = new ReaderWriterLock(hos.Os);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterObserver(TObserver observerHolder)
|
||||||
|
{
|
||||||
|
Assert.False(observerHolder.IsRegistered);
|
||||||
|
|
||||||
|
using ScopedLock<ReaderWriterLock> lk = ScopedLock.Lock(ref _rwLock);
|
||||||
|
|
||||||
|
_observers.AddFirst(observerHolder);
|
||||||
|
observerHolder.IsRegistered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterObserver(TObserver observerHolder)
|
||||||
|
{
|
||||||
|
Assert.True(observerHolder.IsRegistered);
|
||||||
|
|
||||||
|
using ScopedLock<ReaderWriterLock> lk = ScopedLock.Lock(ref _rwLock);
|
||||||
|
|
||||||
|
LinkedListNode<TObserver> foundObserver = _observers.Find(observerHolder);
|
||||||
|
if (foundObserver is not null)
|
||||||
|
{
|
||||||
|
_observers.Remove(foundObserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
observerHolder.IsRegistered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterAllObservers()
|
||||||
|
{
|
||||||
|
using ScopedLock<ReaderWriterLock> lk = ScopedLock.Lock(ref _rwLock);
|
||||||
|
|
||||||
|
LinkedListNode<TObserver> curNode = _observers.First;
|
||||||
|
|
||||||
|
while (curNode is not null)
|
||||||
|
{
|
||||||
|
curNode.ValueRef.IsRegistered = false;
|
||||||
|
curNode = curNode.Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
_observers.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InvokeAllObserver(in TItem item, Function function)
|
||||||
|
{
|
||||||
|
using ScopedLock<ReaderWriterLock> lk = ScopedLock.Lock(ref _rwLock);
|
||||||
|
|
||||||
|
LinkedListNode<TObserver> curNode = _observers.First;
|
||||||
|
|
||||||
|
while (curNode is not null)
|
||||||
|
{
|
||||||
|
function(ref curNode.ValueRef, in item);
|
||||||
|
curNode = curNode.Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Todo: Use generic class when ref structs can be used as generics
|
||||||
|
internal class LogObserverManager
|
||||||
|
{
|
||||||
|
private readonly LinkedList<LogObserverHolder> _observers;
|
||||||
|
private ReaderWriterLock _rwLock;
|
||||||
|
|
||||||
|
public delegate void Function(ref LogObserverHolder observer, in LogObserverContext item);
|
||||||
|
|
||||||
|
public LogObserverManager(HorizonClient hos)
|
||||||
|
{
|
||||||
|
_observers = new LinkedList<LogObserverHolder>();
|
||||||
|
_rwLock = new ReaderWriterLock(hos.Os);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterObserver(LogObserverHolder observerHolder)
|
||||||
|
{
|
||||||
|
Assert.False(observerHolder.IsRegistered);
|
||||||
|
|
||||||
|
using ScopedLock<ReaderWriterLock> lk = ScopedLock.Lock(ref _rwLock);
|
||||||
|
|
||||||
|
_observers.AddFirst(observerHolder);
|
||||||
|
observerHolder.IsRegistered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterObserver(LogObserverHolder observerHolder)
|
||||||
|
{
|
||||||
|
Assert.True(observerHolder.IsRegistered);
|
||||||
|
|
||||||
|
using ScopedLock<ReaderWriterLock> lk = ScopedLock.Lock(ref _rwLock);
|
||||||
|
|
||||||
|
LinkedListNode<LogObserverHolder> foundObserver = _observers.Find(observerHolder);
|
||||||
|
if (foundObserver is not null)
|
||||||
|
{
|
||||||
|
_observers.Remove(foundObserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
observerHolder.IsRegistered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterAllObservers()
|
||||||
|
{
|
||||||
|
using ScopedLock<ReaderWriterLock> lk = ScopedLock.Lock(ref _rwLock);
|
||||||
|
|
||||||
|
LinkedListNode<LogObserverHolder> curNode = _observers.First;
|
||||||
|
|
||||||
|
while (curNode is not null)
|
||||||
|
{
|
||||||
|
curNode.ValueRef.IsRegistered = false;
|
||||||
|
curNode = curNode.Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
_observers.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InvokeAllObserver(in LogObserverContext item, Function function)
|
||||||
|
{
|
||||||
|
using ScopedLock<ReaderWriterLock> lk = ScopedLock.Lock(ref _rwLock);
|
||||||
|
|
||||||
|
LinkedListNode<LogObserverHolder> curNode = _observers.First;
|
||||||
|
|
||||||
|
while (curNode is not null)
|
||||||
|
{
|
||||||
|
function(ref curNode.ValueRef, in item);
|
||||||
|
curNode = curNode.Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
src/LibHac/Diag/Log.cs
Normal file
47
src/LibHac/Diag/Log.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using LibHac.Common;
|
||||||
|
|
||||||
|
namespace LibHac.Diag
|
||||||
|
{
|
||||||
|
public static class Log
|
||||||
|
{
|
||||||
|
// Todo: Should we split large logs into smaller chunks like Horizon does?
|
||||||
|
public static void LogImpl(this DiagClientImpl diag, in LogMetaData metaData, ReadOnlySpan<byte> message)
|
||||||
|
{
|
||||||
|
diag.PutImpl(in metaData, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PutImpl(this DiagClientImpl diag, in LogMetaData metaData, ReadOnlySpan<byte> message)
|
||||||
|
{
|
||||||
|
var logBody = new LogBody
|
||||||
|
{
|
||||||
|
Message = new U8Span(message),
|
||||||
|
IsHead = true,
|
||||||
|
IsTail = true
|
||||||
|
};
|
||||||
|
|
||||||
|
diag.CallAllLogObserver(in metaData, in logBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogImpl(this DiagClientImpl diag, ReadOnlySpan<byte> moduleName, LogSeverity severity,
|
||||||
|
ReadOnlySpan<byte> message, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string fileName = "",
|
||||||
|
[CallerMemberName] string functionName = "")
|
||||||
|
{
|
||||||
|
var metaData = new LogMetaData
|
||||||
|
{
|
||||||
|
SourceInfo = new SourceInfo
|
||||||
|
{
|
||||||
|
LineNumber = lineNumber,
|
||||||
|
FileName = fileName,
|
||||||
|
FunctionName = functionName
|
||||||
|
},
|
||||||
|
ModuleName = new U8Span(moduleName),
|
||||||
|
Severity = severity,
|
||||||
|
Verbosity = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
diag.LogImpl(in metaData, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
src/LibHac/Diag/LogObserver.cs
Normal file
110
src/LibHac/Diag/LogObserver.cs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Diag.Impl;
|
||||||
|
|
||||||
|
namespace LibHac.Diag
|
||||||
|
{
|
||||||
|
public delegate void LogObserver(in LogMetaData metaData, in LogBody body, object arguments);
|
||||||
|
|
||||||
|
internal struct LogObserverGlobals
|
||||||
|
{
|
||||||
|
public LogObserverHolder DefaultLogObserverHolder;
|
||||||
|
|
||||||
|
public nint ManagerGuard;
|
||||||
|
public LogObserverManager Manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LogObserverHolder
|
||||||
|
{
|
||||||
|
internal LogObserver Observer;
|
||||||
|
internal bool IsRegistered;
|
||||||
|
internal object Arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LogObserverFuncs
|
||||||
|
{
|
||||||
|
public static void InitializeLogObserverHolder(this DiagClient diag, ref LogObserverHolder holder,
|
||||||
|
LogObserver observer, object arguments)
|
||||||
|
{
|
||||||
|
holder.Observer = observer;
|
||||||
|
holder.IsRegistered = false;
|
||||||
|
holder.Arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterLogObserver(this DiagClient diag, LogObserverHolder observerHolder)
|
||||||
|
{
|
||||||
|
diag.Impl.GetLogObserverManager().RegisterObserver(observerHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnregisterLogObserver(this DiagClient diag, LogObserverHolder observerHolder)
|
||||||
|
{
|
||||||
|
diag.Impl.GetLogObserverManager().UnregisterObserver(observerHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TentativeDefaultLogObserver(in LogMetaData metaData, in LogBody body, object arguments)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LogObserverManager GetLogObserverManager(this DiagClientImpl diag)
|
||||||
|
{
|
||||||
|
ref LogObserverGlobals g = ref diag.Globals.LogObserver;
|
||||||
|
using var guard = new InitializationGuard(ref g.ManagerGuard, diag.Globals.InitMutex);
|
||||||
|
|
||||||
|
if (!guard.IsInitialized)
|
||||||
|
{
|
||||||
|
g.Manager = new LogObserverManager(diag.Hos);
|
||||||
|
g.DefaultLogObserverHolder = new LogObserverHolder();
|
||||||
|
diag.Diag.InitializeLogObserverHolder(ref g.DefaultLogObserverHolder, TentativeDefaultLogObserver, null);
|
||||||
|
g.Manager.RegisterObserver(g.DefaultLogObserverHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g.Manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void CallAllLogObserver(this DiagClientImpl diag, in LogMetaData metaData, in LogBody body)
|
||||||
|
{
|
||||||
|
var context = new LogObserverContext
|
||||||
|
{
|
||||||
|
MetaData = metaData,
|
||||||
|
Body = body
|
||||||
|
};
|
||||||
|
|
||||||
|
LogObserverManager manager = diag.GetLogObserverManager();
|
||||||
|
|
||||||
|
manager.InvokeAllObserver(in context, InvokeFunction);
|
||||||
|
|
||||||
|
static void InvokeFunction(ref LogObserverHolder holder, in LogObserverContext item)
|
||||||
|
{
|
||||||
|
holder.Observer(in item.MetaData, in item.Body, holder.Arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ReplaceDefaultLogObserver(this DiagClientImpl diag, LogObserver observer)
|
||||||
|
{
|
||||||
|
ref LogObserverGlobals g = ref diag.Globals.LogObserver;
|
||||||
|
|
||||||
|
diag.Diag.UnregisterLogObserver(g.DefaultLogObserverHolder);
|
||||||
|
diag.Diag.InitializeLogObserverHolder(ref g.DefaultLogObserverHolder, observer, null);
|
||||||
|
diag.Diag.RegisterLogObserver(g.DefaultLogObserverHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ResetDefaultLogObserver(this DiagClientImpl diag)
|
||||||
|
{
|
||||||
|
ref LogObserverGlobals g = ref diag.Globals.LogObserver;
|
||||||
|
|
||||||
|
diag.Diag.UnregisterLogObserver(g.DefaultLogObserverHolder);
|
||||||
|
diag.Diag.InitializeLogObserverHolder(ref g.DefaultLogObserverHolder, TentativeDefaultLogObserver, null);
|
||||||
|
diag.Diag.RegisterLogObserver(g.DefaultLogObserverHolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace LibHac.Diag.Impl
|
||||||
|
{
|
||||||
|
// Todo: Make fields references once C# 10 is released
|
||||||
|
internal ref struct LogObserverContext
|
||||||
|
{
|
||||||
|
public LogMetaData MetaData;
|
||||||
|
public LogBody Body;
|
||||||
|
}
|
||||||
|
}
|
38
src/LibHac/Diag/LogTypes.cs
Normal file
38
src/LibHac/Diag/LogTypes.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
|
|
||||||
|
namespace LibHac.Diag
|
||||||
|
{
|
||||||
|
public enum LogSeverity
|
||||||
|
{
|
||||||
|
Trace,
|
||||||
|
Info,
|
||||||
|
Warn,
|
||||||
|
Error,
|
||||||
|
Fatal
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref struct LogMetaData
|
||||||
|
{
|
||||||
|
public SourceInfo SourceInfo;
|
||||||
|
public U8Span ModuleName;
|
||||||
|
public LogSeverity Severity;
|
||||||
|
public int Verbosity;
|
||||||
|
public bool UseDefaultLocaleCharset;
|
||||||
|
public Span<byte> AdditionalData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct SourceInfo
|
||||||
|
{
|
||||||
|
public int LineNumber;
|
||||||
|
public string FileName;
|
||||||
|
public string FunctionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref struct LogBody
|
||||||
|
{
|
||||||
|
public U8Span Message;
|
||||||
|
public bool IsHead;
|
||||||
|
public bool IsTail;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ namespace LibHac
|
||||||
{
|
{
|
||||||
_currentProcessId = InitialProcessCountMax;
|
_currentProcessId = InitialProcessCountMax;
|
||||||
|
|
||||||
TickGenerator = config.TickGenerator;
|
TickGenerator = config.TickGenerator ?? new DefaultTickGenerator();
|
||||||
ServiceManager = new ServiceManager();
|
ServiceManager = new ServiceManager();
|
||||||
|
|
||||||
LoaderClient = CreatePrivilegedHorizonClient();
|
LoaderClient = CreatePrivilegedHorizonClient();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using LibHac.Arp;
|
using LibHac.Arp;
|
||||||
|
using LibHac.Diag;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Lr;
|
using LibHac.Lr;
|
||||||
using LibHac.Os;
|
using LibHac.Os;
|
||||||
|
@ -18,6 +19,7 @@ namespace LibHac
|
||||||
public FileSystemClient Fs { get; }
|
public FileSystemClient Fs { get; }
|
||||||
public ServiceManagerClient Sm { get; }
|
public ServiceManagerClient Sm { get; }
|
||||||
public OsState Os { get; }
|
public OsState Os { get; }
|
||||||
|
public DiagClient Diag { get; }
|
||||||
public LrClient Lr { get; }
|
public LrClient Lr { get; }
|
||||||
public ArpClient Arp => ArpLazy.Value;
|
public ArpClient Arp => ArpLazy.Value;
|
||||||
|
|
||||||
|
@ -29,6 +31,7 @@ namespace LibHac
|
||||||
Fs = new FileSystemClient(this);
|
Fs = new FileSystemClient(this);
|
||||||
Sm = new ServiceManagerClient(Horizon.ServiceManager);
|
Sm = new ServiceManagerClient(Horizon.ServiceManager);
|
||||||
Os = new OsState(this, horizon.TickGenerator);
|
Os = new OsState(this, horizon.TickGenerator);
|
||||||
|
Diag = new DiagClient(this);
|
||||||
Lr = new LrClient(this);
|
Lr = new LrClient(this);
|
||||||
|
|
||||||
ArpLazy = new Lazy<ArpClient>(InitArpClient, true);
|
ArpLazy = new Lazy<ArpClient>(InitArpClient, true);
|
||||||
|
|
|
@ -14,9 +14,4 @@ namespace LibHac
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ITickGenerator? TickGenerator { get; set; }
|
public ITickGenerator? TickGenerator { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ITickGenerator
|
|
||||||
{
|
|
||||||
Tick GetCurrentTick();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
24
src/LibHac/Os/ITickGenerator.cs
Normal file
24
src/LibHac/Os/ITickGenerator.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace LibHac.Os
|
||||||
|
{
|
||||||
|
public interface ITickGenerator
|
||||||
|
{
|
||||||
|
Tick GetCurrentTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultTickGenerator : ITickGenerator
|
||||||
|
{
|
||||||
|
private readonly long _initialTick;
|
||||||
|
|
||||||
|
public DefaultTickGenerator()
|
||||||
|
{
|
||||||
|
_initialTick = Stopwatch.GetTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tick GetCurrentTick()
|
||||||
|
{
|
||||||
|
return new Tick(Stopwatch.GetTimestamp() - _initialTick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Common.Keys;
|
using LibHac.Common.Keys;
|
||||||
using LibHac.Fs;
|
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
|
|
||||||
namespace hactoolnet
|
namespace hactoolnet
|
||||||
|
@ -100,6 +99,6 @@ namespace hactoolnet
|
||||||
public Options Options;
|
public Options Options;
|
||||||
public KeySet KeySet;
|
public KeySet KeySet;
|
||||||
public ProgressBar Logger;
|
public ProgressBar Logger;
|
||||||
public FileSystemClient FsClient;
|
public HorizonClient Horizon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using LibHac;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
|
using LibHac.Fs.Impl;
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
using LibHac.FsSystem.NcaUtils;
|
using LibHac.FsSystem.NcaUtils;
|
||||||
using LibHac.Npdm;
|
using LibHac.Npdm;
|
||||||
|
@ -45,7 +46,7 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.SectionOutDir[i] != null)
|
if (ctx.Options.SectionOutDir[i] != null)
|
||||||
{
|
{
|
||||||
FileSystemClient fs = ctx.FsClient;
|
FileSystemClient fs = ctx.Horizon.Fs;
|
||||||
|
|
||||||
string mountName = $"section{i}";
|
string mountName = $"section{i}";
|
||||||
|
|
||||||
|
@ -96,11 +97,14 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.RomfsOutDir != null)
|
if (ctx.Options.RomfsOutDir != null)
|
||||||
{
|
{
|
||||||
FileSystemClient fs = ctx.FsClient;
|
FileSystemClient fs = ctx.Horizon.Fs;
|
||||||
|
|
||||||
fs.Register("rom".ToU8Span(), OpenFileSystemByType(NcaSectionType.Data));
|
fs.Register("rom".ToU8Span(), OpenFileSystemByType(NcaSectionType.Data));
|
||||||
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir));
|
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir));
|
||||||
|
|
||||||
|
fs.Impl.EnableFileSystemAccessorAccessLog("rom".ToU8Span());
|
||||||
|
fs.Impl.EnableFileSystemAccessorAccessLog("output".ToU8Span());
|
||||||
|
|
||||||
FsUtils.CopyDirectoryWithProgress(fs, "rom:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();
|
FsUtils.CopyDirectoryWithProgress(fs, "rom:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();
|
||||||
|
|
||||||
fs.Unmount("rom".ToU8Span());
|
fs.Unmount("rom".ToU8Span());
|
||||||
|
@ -153,7 +157,7 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.ExefsOutDir != null)
|
if (ctx.Options.ExefsOutDir != null)
|
||||||
{
|
{
|
||||||
FileSystemClient fs = ctx.FsClient;
|
FileSystemClient fs = ctx.Horizon.Fs;
|
||||||
|
|
||||||
fs.Register("code".ToU8Span(), OpenFileSystemByType(NcaSectionType.Code));
|
fs.Register("code".ToU8Span(), OpenFileSystemByType(NcaSectionType.Code));
|
||||||
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir));
|
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir));
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace hactoolnet
|
||||||
bool signNeeded = ctx.Options.SignSave;
|
bool signNeeded = ctx.Options.SignSave;
|
||||||
|
|
||||||
var save = new SaveDataFileSystem(ctx.KeySet, file, ctx.Options.IntegrityLevel, true);
|
var save = new SaveDataFileSystem(ctx.KeySet, file, ctx.Options.IntegrityLevel, true);
|
||||||
FileSystemClient fs = ctx.FsClient;
|
FileSystemClient fs = ctx.Horizon.Fs;
|
||||||
|
|
||||||
fs.Register("save".ToU8Span(), save);
|
fs.Register("save".ToU8Span(), save);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Common.Keys;
|
using LibHac.Common.Keys;
|
||||||
|
using LibHac.Diag;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Util;
|
using LibHac.Util;
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ namespace hactoolnet
|
||||||
|
|
||||||
StreamWriter logWriter = null;
|
StreamWriter logWriter = null;
|
||||||
ResultLogger resultLogger = null;
|
ResultLogger resultLogger = null;
|
||||||
|
LogObserverHolder logObserver = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -71,14 +73,23 @@ namespace hactoolnet
|
||||||
|
|
||||||
Horizon horizon = HorizonFactory.CreateWithDefaultFsConfig(new HorizonConfiguration(),
|
Horizon horizon = HorizonFactory.CreateWithDefaultFsConfig(new HorizonConfiguration(),
|
||||||
new InMemoryFileSystem(), ctx.KeySet);
|
new InMemoryFileSystem(), ctx.KeySet);
|
||||||
ctx.FsClient = horizon.CreatePrivilegedHorizonClient().Fs;
|
ctx.Horizon = horizon.CreatePrivilegedHorizonClient();
|
||||||
|
|
||||||
if (ctx.Options.AccessLog != null)
|
if (ctx.Options.AccessLog != null)
|
||||||
{
|
{
|
||||||
logWriter = new StreamWriter(ctx.Options.AccessLog);
|
logWriter = new StreamWriter(ctx.Options.AccessLog);
|
||||||
|
logObserver = new LogObserverHolder();
|
||||||
|
|
||||||
ctx.FsClient.SetLocalSystemAccessLogForDebug(true);
|
// ReSharper disable once AccessToDisposedClosure
|
||||||
ctx.FsClient.SetGlobalAccessLogMode(GlobalAccessLogMode.Log);
|
// References to logWriter should be gone by the time it's disposed
|
||||||
|
ctx.Horizon.Diag.InitializeLogObserverHolder(ref logObserver,
|
||||||
|
(in LogMetaData data, in LogBody body, object arguments) =>
|
||||||
|
logWriter.Write(body.Message.ToString()), null);
|
||||||
|
|
||||||
|
ctx.Horizon.Diag.RegisterLogObserver(logObserver);
|
||||||
|
|
||||||
|
ctx.Horizon.Fs.SetLocalSystemAccessLogForDebug(true);
|
||||||
|
ctx.Horizon.Fs.SetGlobalAccessLogMode(GlobalAccessLogMode.Log).ThrowIfFailure();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.ResultLog != null)
|
if (ctx.Options.ResultLog != null)
|
||||||
|
@ -100,6 +111,11 @@ namespace hactoolnet
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
if (logObserver != null)
|
||||||
|
{
|
||||||
|
ctx.Horizon.Diag.UnregisterLogObserver(logObserver);
|
||||||
|
}
|
||||||
|
|
||||||
logWriter?.Dispose();
|
logWriter?.Dispose();
|
||||||
|
|
||||||
if (resultLogger != null)
|
if (resultLogger != null)
|
||||||
|
|
Loading…
Reference in a new issue