diff --git a/src/LibHac/Common/U8StringHelpers.cs b/src/LibHac/Common/U8StringHelpers.cs index 003b61fb..5dcae1ce 100644 --- a/src/LibHac/Common/U8StringHelpers.cs +++ b/src/LibHac/Common/U8StringHelpers.cs @@ -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); } diff --git a/src/LibHac/Fs/AccessLogHelpers.cs b/src/LibHac/Fs/AccessLogHelpers.cs new file mode 100644 index 00000000..7fd00695 --- /dev/null +++ b/src/LibHac/Fs/AccessLogHelpers.cs @@ -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} }}"; + } + } +} diff --git a/src/LibHac/Fs/FileSystemClient.AccessLog.cs b/src/LibHac/Fs/FileSystemClient.AccessLog.cs index f291ba80..0df0f797 100644 --- a/src/LibHac/Fs/FileSystemClient.AccessLog.cs +++ b/src/LibHac/Fs/FileSystemClient.AccessLog.cs @@ -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 operation, Func 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 operation, + Func textGenerator, [CallerMemberName] string caller = "") { Result rc; @@ -93,6 +177,27 @@ namespace LibHac.Fs return rc; } + + public Result RunOperationWithAccessLog(LocalAccessLogMode logType, FileHandle handle, Func operation, + Func 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] diff --git a/src/LibHac/Fs/FileSystemClient.File.cs b/src/LibHac/Fs/FileSystemClient.File.cs index 3e508426..aab0c161 100644 --- a/src/LibHac/Fs/FileSystemClient.File.cs +++ b/src/LibHac/Fs/FileSystemClient.File.cs @@ -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); } } } diff --git a/src/LibHac/Fs/FileSystemClient.cs b/src/LibHac/Fs/FileSystemClient.cs index 391e40ea..d4957282 100644 --- a/src/LibHac/Fs/FileSystemClient.cs +++ b/src/LibHac/Fs/FileSystemClient.cs @@ -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 path, out FileSystemAccessor fileSystem, out ReadOnlySpan 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); - } } } diff --git a/src/hactoolnet/AccessLog.cs b/src/hactoolnet/AccessLog.cs index 789965c6..67ba128f 100644 --- a/src/hactoolnet/AccessLog.cs +++ b/src/hactoolnet/AccessLog.cs @@ -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)); } } } diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index dc640f5d..f6125e29 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -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); diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index a225d382..1a18db38 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -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"); diff --git a/src/hactoolnet/Program.cs b/src/hactoolnet/Program.cs index a1222357..84ed4fb8 100644 --- a/src/hactoolnet/Program.cs +++ b/src/hactoolnet/Program.cs @@ -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);