Add an option to control which types of access events are logged

This commit is contained in:
Alex Barney 2019-09-30 16:15:31 -05:00
parent 22bbf07c2b
commit 5011a57d3e
9 changed files with 172 additions and 137 deletions

View file

@ -2,12 +2,12 @@
{
public static class U8StringHelpers
{
public static U8String AsU8String(this string value)
public static U8String ToU8String(this string value)
{
return new U8String(value);
}
public static U8Span AsU8Span(this string value)
public static U8Span ToU8Span(this string value)
{
return new U8Span(value);
}

View file

@ -0,0 +1,14 @@
using System;
namespace LibHac.Fs
{
public static class AccessLogHelpers
{
public static string BuildDefaultLogLine(Result result, TimeSpan startTime, TimeSpan endTime, int handleId,
string message, string caller)
{
return
$"FS_ACCESS: {{ start: {(long) startTime.TotalMilliseconds,9}, end: {(long) endTime.TotalMilliseconds,9}, result: 0x{result.Value:x8}, handle: 0x{handleId:x8}, function: \"{caller}\"{message} }}";
}
}
}

View file

@ -1,5 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Fs.Accessors;
using LibHac.FsService;
namespace LibHac.Fs
@ -14,16 +16,28 @@ namespace LibHac.Fs
public Result GetGlobalAccessLogMode(out GlobalAccessLogMode mode)
{
IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject();
if (HasFileSystemServer())
{
IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject();
return fsProxy.GetGlobalAccessLogMode(out mode);
return fsProxy.GetGlobalAccessLogMode(out mode);
}
mode = GlobalAccessLogMode;
return Result.Success;
}
public Result SetGlobalAccessLogMode(GlobalAccessLogMode mode)
{
IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject();
if (HasFileSystemServer())
{
IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject();
return fsProxy.SetGlobalAccessLogMode(mode);
return fsProxy.SetGlobalAccessLogMode(mode);
}
GlobalAccessLogMode = mode;
return Result.Success;
}
public void SetLocalAccessLogMode(LocalAccessLogMode mode)
@ -31,6 +45,11 @@ namespace LibHac.Fs
LocalAccessLogMode = mode;
}
public void SetAccessLogObject(IAccessLog accessLog)
{
AccessLog = accessLog;
}
internal bool IsEnabledAccessLog(LocalAccessLogMode mode)
{
if ((LocalAccessLogMode & mode) == 0)
@ -47,14 +66,21 @@ namespace LibHac.Fs
{
if (!AccessLogInitialized)
{
IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject();
Result rc = fsProxy.GetGlobalAccessLogMode(out GlobalAccessLogMode globalMode);
GlobalAccessLogMode = globalMode;
if (rc.IsFailure())
if (HasFileSystemServer())
{
throw new LibHacException("Abort");
IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject();
Result rc = fsProxy.GetGlobalAccessLogMode(out GlobalAccessLogMode globalMode);
GlobalAccessLogMode = globalMode;
if (rc.IsFailure())
{
throw new LibHacException("Abort");
}
}
else
{
GlobalAccessLogMode = GlobalAccessLogMode.Log;
}
if (GlobalAccessLogMode != GlobalAccessLogMode.None)
@ -74,7 +100,65 @@ namespace LibHac.Fs
}
public Result RunOperationWithAccessLog(LocalAccessLogMode logType, Func<Result> operation, Func<string> textGenerator, [CallerMemberName] string caller = "")
internal bool IsEnabledAccessLog()
{
return IsEnabledAccessLog(LocalAccessLogMode.All);
}
internal bool IsEnabledFileSystemAccessorAccessLog(string mountName)
{
if (MountTable.Find(mountName, out FileSystemAccessor accessor).IsFailure())
{
return true;
}
return accessor.IsAccessLogEnabled;
}
internal bool IsEnabledHandleAccessLog(FileHandle handle)
{
return handle.File.Parent.IsAccessLogEnabled;
}
internal bool IsEnabledHandleAccessLog(DirectoryHandle handle)
{
return handle.Directory.Parent.IsAccessLogEnabled;
}
internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "")
{
OutputAccessLogImpl(result, startTime, endTime, 0, message, caller);
}
internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "")
{
OutputAccessLogImpl(result, startTime, endTime, handle.GetId(), message, caller);
}
internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "")
{
OutputAccessLogImpl(result, startTime, endTime, handle.GetId(), message, caller);
}
internal void OutputAccessLogImpl(Result result, TimeSpan startTime, TimeSpan endTime, int handleId,
string message, [CallerMemberName] string caller = "")
{
if (GlobalAccessLogMode.HasFlag(GlobalAccessLogMode.Log))
{
AccessLog?.Log(result, startTime, endTime, handleId, message, caller);
}
if (GlobalAccessLogMode.HasFlag(GlobalAccessLogMode.SdCard))
{
string logString = AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller);
IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject();
fsProxy.OutputAccessLogToSdCard(logString.ToU8Span());
}
}
public Result RunOperationWithAccessLog(LocalAccessLogMode logType, Func<Result> operation,
Func<string> textGenerator, [CallerMemberName] string caller = "")
{
Result rc;
@ -93,6 +177,27 @@ namespace LibHac.Fs
return rc;
}
public Result RunOperationWithAccessLog(LocalAccessLogMode logType, FileHandle handle, Func<Result> operation,
Func<string> textGenerator, [CallerMemberName] string caller = "")
{
Result rc;
if (IsEnabledAccessLog(logType) && handle.File.Parent.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = operation();
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, textGenerator(), caller);
}
else
{
rc = operation();
}
return rc;
}
}
[Flags]

View file

@ -73,22 +73,9 @@ namespace LibHac.Fs
public Result FlushFile(FileHandle handle)
{
Result rc;
if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle))
{
TimeSpan startTime = Time.GetCurrent();
rc = handle.File.Flush();
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, handle, string.Empty);
}
else
{
rc = handle.File.Flush();
}
return rc;
return RunOperationWithAccessLog(LocalAccessLogMode.All, handle,
() => handle.File.Flush(),
() => string.Empty);
}
public Result GetFileSize(out long fileSize, FileHandle handle)
@ -98,22 +85,9 @@ namespace LibHac.Fs
public Result SetFileSize(FileHandle handle, long size)
{
Result rc;
if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle))
{
TimeSpan startTime = Time.GetCurrent();
rc = handle.File.SetSize(size);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, handle, $", size: {size}");
}
else
{
rc = handle.File.SetSize(size);
}
return rc;
return RunOperationWithAccessLog(LocalAccessLogMode.All, handle,
() => handle.File.SetSize(size),
() => $", size: {size}");
}
public OpenMode GetFileOpenMode(FileHandle handle)
@ -123,18 +97,13 @@ namespace LibHac.Fs
public void CloseFile(FileHandle handle)
{
if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle))
{
TimeSpan startTime = Time.GetCurrent();
handle.File.Dispose();
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty);
}
else
{
handle.File.Dispose();
}
RunOperationWithAccessLog(LocalAccessLogMode.All, handle,
() =>
{
handle.File.Dispose();
return Result.Success;
},
() => string.Empty);
}
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Fs.Accessors;
using LibHac.FsService;
@ -16,19 +15,23 @@ namespace LibHac.Fs
internal ITimeSpanGenerator Time { get; }
private IAccessLog AccessLog { get; set; }
private bool AccessLogEnabled { get; set; }
internal MountTable MountTable { get; } = new MountTable();
public FileSystemClient(ITimeSpanGenerator timer)
{
Time = timer;
Time = timer ?? new StopWatchTimeSpanGenerator();
}
public FileSystemClient(FileSystemServer fsServer, ITimeSpanGenerator timer)
{
FsSrv = fsServer;
Time = timer;
Time = timer ?? new StopWatchTimeSpanGenerator();
}
public bool HasFileSystemServer()
{
return FsSrv != null;
}
public IFileSystemProxy GetFileSystemProxyServiceObject()
@ -39,7 +42,7 @@ namespace LibHac.Fs
{
if (FsProxy != null) return FsProxy;
if (FsSrv == null)
if (!HasFileSystemServer())
{
throw new InvalidOperationException("Client was not initialized with a server object.");
}
@ -87,18 +90,6 @@ namespace LibHac.Fs
rc.ThrowIfFailure();
}
public void SetAccessLog(bool isEnabled, IAccessLog accessLog = null)
{
AccessLogEnabled = isEnabled;
if (isEnabled && FsSrv != null)
{
SetGlobalAccessLogMode(GlobalAccessLogMode.All);
}
if (accessLog != null) AccessLog = accessLog;
}
internal Result FindFileSystem(ReadOnlySpan<char> path, out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath)
{
fileSystem = default;
@ -147,45 +138,5 @@ namespace LibHac.Fs
return Result.Success;
}
internal bool IsEnabledAccessLog()
{
return AccessLogEnabled && AccessLog != null && Time != null;
}
internal bool IsEnabledFileSystemAccessorAccessLog(string mountName)
{
if (MountTable.Find(mountName, out FileSystemAccessor accessor).IsFailure())
{
return true;
}
return accessor.IsAccessLogEnabled;
}
internal bool IsEnabledHandleAccessLog(FileHandle handle)
{
return handle.File.Parent.IsAccessLogEnabled;
}
internal bool IsEnabledHandleAccessLog(DirectoryHandle handle)
{
return handle.Directory.Parent.IsAccessLogEnabled;
}
internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "")
{
AccessLog.Log(result, startTime, endTime, 0, message, caller);
}
internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "")
{
AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller);
}
internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "")
{
AccessLog.Log(result, startTime, endTime, handle.GetId(), message, caller);
}
}
}

View file

@ -10,7 +10,7 @@ namespace hactoolnet
{
public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "")
{
Console.WriteLine(CommonAccessLog.BuildLogLine(result, startTime, endTime, handleId, message, caller));
Console.WriteLine(AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller));
}
}
@ -24,7 +24,7 @@ namespace hactoolnet
public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "")
{
Logger.LogMessage(CommonAccessLog.BuildLogLine(result, startTime, endTime, handleId, message, caller));
Logger.LogMessage(AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller));
}
}
@ -39,16 +39,7 @@ namespace hactoolnet
public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "")
{
Logger.WriteLine(CommonAccessLog.BuildLogLine(result, startTime, endTime, handleId, message, caller));
}
}
public static class CommonAccessLog
{
public static string BuildLogLine(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message,
string caller)
{
return $"FS_ACCESS: {{ start: {(long)startTime.TotalMilliseconds,9}, end: {(long)endTime.TotalMilliseconds,9}, result: 0x{result.Value:x8}, handle: 0x{handleId:x8}, function: \"{caller}\"{message} }}";
Logger.WriteLine(AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller));
}
}
}

View file

@ -48,8 +48,8 @@ namespace hactoolnet
string mountName = $"section{i}";
fs.Register(mountName.AsU8Span(), OpenFileSystem(i));
fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.SectionOutDir[i]));
fs.Register(mountName.ToU8Span(), OpenFileSystem(i));
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.SectionOutDir[i]));
FsUtils.CopyDirectoryWithProgress(fs, mountName + ":/", "output:/", logger: ctx.Logger);
@ -97,8 +97,8 @@ namespace hactoolnet
{
FileSystemClient fs = ctx.Horizon.Fs;
fs.Register("rom".AsU8Span(), OpenFileSystemByType(NcaSectionType.Data));
fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir));
fs.Register("rom".ToU8Span(), OpenFileSystemByType(NcaSectionType.Data));
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir));
FsUtils.CopyDirectoryWithProgress(fs, "rom:/", "output:/", logger: ctx.Logger);
@ -154,8 +154,8 @@ namespace hactoolnet
{
FileSystemClient fs = ctx.Horizon.Fs;
fs.Register("code".AsU8Span(), OpenFileSystemByType(NcaSectionType.Code));
fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir));
fs.Register("code".ToU8Span(), OpenFileSystemByType(NcaSectionType.Code));
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir));
FsUtils.CopyDirectoryWithProgress(fs, "code:/", "output:/", logger: ctx.Logger);

View file

@ -31,7 +31,7 @@ namespace hactoolnet
var save = new SaveDataFileSystem(ctx.Keyset, file, ctx.Options.IntegrityLevel, true);
FileSystemClient fs = ctx.Horizon.Fs;
fs.Register("save".AsU8Span(), save);
fs.Register("save".ToU8Span(), save);
if (ctx.Options.Validate)
{
@ -40,7 +40,7 @@ namespace hactoolnet
if (ctx.Options.OutDir != null)
{
fs.Register("output".AsU8Span(), new LocalFileSystem(ctx.Options.OutDir));
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.OutDir));
FsUtils.CopyDirectoryWithProgress(fs, "save:/", "output:/", logger: ctx.Logger);
@ -86,7 +86,7 @@ namespace hactoolnet
if (ctx.Options.RepackSource != null)
{
fs.Register("input".AsU8Span(), new LocalFileSystem(ctx.Options.RepackSource));
fs.Register("input".ToU8Span(), new LocalFileSystem(ctx.Options.RepackSource));
fs.CleanDirectoryRecursively("save:/");
fs.Commit("save");

View file

@ -2,6 +2,7 @@
using System.IO;
using System.Text;
using LibHac;
using LibHac.Fs;
namespace hactoolnet
{
@ -63,7 +64,11 @@ namespace hactoolnet
{
logWriter = new StreamWriter(ctx.Options.AccessLog);
var accessLog = new TextWriterAccessLog(logWriter);
ctx.Horizon.Fs.SetAccessLog(true, accessLog);
ctx.Horizon.Fs.SetLocalAccessLogMode(LocalAccessLogMode.All);
ctx.Horizon.Fs.SetGlobalAccessLogMode(GlobalAccessLogMode.Log);
ctx.Horizon.Fs.SetAccessLogObject(accessLog);
}
OpenKeyset(ctx);