using Ionic.Zlib; using System; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; namespace IPA.Logging.Printers { /// /// A abstract class that provides the utilities to write to a GZip file. /// public abstract class GZFilePrinter : LogPrinter, IDisposable { [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool CreateHardLink( string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes ); internal static Regex removeControlCodes = new Regex("\x1b\\[\\d+m", RegexOptions.Compiled); private FileInfo fileInfo; /// /// The that writes to the GZip file. /// protected StreamWriter FileWriter; private GZipStream zstream; private FileStream fstream; /// /// Gets the for the file to write to without the .gz extension. /// /// protected abstract FileInfo GetFileInfo(); private void InitLog() { try { if (fileInfo == null) { // first init fileInfo = GetFileInfo(); var ext = fileInfo.Extension; fileInfo = new FileInfo(fileInfo.FullName + ".gz"); fileInfo.Create().Close(); var symlink = new FileInfo(Path.Combine(fileInfo.DirectoryName ?? throw new InvalidOperationException(), $"_latest{ext}.gz")); if (symlink.Exists) symlink.Delete(); try { if (!CreateHardLink(symlink.FullName, fileInfo.FullName, IntPtr.Zero)) { var error = Marshal.GetLastWin32Error(); Logger.log.Error($"Hardlink creation failed ({error})"); } } catch (Exception e) { Logger.log.Error("Error creating latest hardlink!"); Logger.log.Error(e); } } } catch (Exception e) { Logger.log.Error("Error initializing log!"); Logger.log.Error(e); } } /// /// Called at the start of any print session. /// public sealed override void StartPrint() { InitLog(); fstream = fileInfo.Open(FileMode.Append, FileAccess.Write); zstream = new GZipStream(fstream, CompressionMode.Compress) { FlushMode = FlushType.Full }; FileWriter = new StreamWriter(zstream, new UTF8Encoding(false)); } /// /// Called at the end of any print session. /// public sealed override void EndPrint() { FileWriter.Flush(); zstream.Flush(); fstream.Flush(); FileWriter.Dispose(); zstream.Dispose(); fstream.Dispose(); FileWriter = null; zstream = null; fstream = null; } /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Disposes the file printer. /// /// does nothing protected virtual void Dispose(bool disposing) { if (disposing) { FileWriter.Flush(); zstream.Flush(); fstream.Flush(); FileWriter.Close(); zstream.Close(); fstream.Close(); FileWriter.Dispose(); zstream.Dispose(); fstream.Dispose(); } } } }