context: #region License
  
  // Copyright (c) 2012, ClearCanvas Inc.
  // All rights reserved.
  // http://www.ClearCanvas.ca
  //
  // This file is part of the ClearCanvas RIS/PACS open source project.
  //
  // The ClearCanvas RIS/PACS open source project is free software: you can
  // redistribute it and/or modify it under the terms of the GNU Lesser Public
  // License as published by the Free Software Foundation, either version 3 of
  // the License, or (at your option) any later version.
  //
  // The ClearCanvas RIS/PACS open source project is distributed in the hope that
  // it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU Lesser Public License for more details.
  //
  // You should have received a copy of the GNU Lesser Public License along with
  // the ClearCanvas RIS/PACS open source project.  If not, see
  // <http://www.gnu.org/licenses/>.
  
  #endregion
  
  #region Inline Attributions
  // The source code contained in this file is based on an original work
  // from the Apache Software Foundation that was licensed under the 
  // Apache License, Version 2.0 a copy of which is located at
  //
  // http://www.apache.org/licenses/LICENSE-2.0
  
  #endregion
  
  using System;
  using System.IO;
  using System.Text;
  using System.Threading;
  using log4net.Appender;
  using log4net.Core;
  using log4net.Layout;
  using log4net.Util;
  using System.Security.AccessControl;
  using System.Security.Principal;
  
  namespace Macro.Common.log4net
  {
      /// <summary>
      /// Appends logging events to a file.
      /// </summary>
      /// <remarks>
      /// <para>
      /// Logging events are sent to the file specified by
      /// the <see cref="File"/> property.
      /// </para>
      /// <para>
      /// The file can be opened in either append or overwrite mode 
      /// by specifying the <see cref="AppendToFile"/> property.
      /// If the file path is relative it is taken as relative from 
      /// the application base directory. The file encoding can be
      /// specified by setting the <see cref="Encoding"/> property.
      /// </para>
      /// <para>
      /// The layout's <see cref="ILayout.Header"/> and <see cref="ILayout.Footer"/>
      /// values will be written each time the file is opened and closed
      /// respectively. If the <see cref="AppendToFile"/> property is <see langword="true"/>
      /// then the file may contain multiple copies of the header and footer.
      /// </para>
      /// <para>
      /// This appender will first try to open the file for writing when <see cref="ActivateOptions"/>
      /// is called. This will typically be during configuration.
      /// If the file cannot be opened for writing the appender will attempt
      /// to open the file again each time a message is logged to the appender.
      /// If the file cannot be opened for writing when a message is logged then
      /// the message will be discarded by this appender.
      /// </para>
      /// <para>
      /// The <see cref="FileAppender"/> supports pluggable file locking models via
      /// the <see cref="LockingModel"/> property.
      /// The default behavior, implemented by <see cref="FileAppender.MutexLock"/> 
      /// is to use a Mutex to lock the file across processe
      /// </para>
      /// </remarks>
      /// <author>Nicko Cadell</author>
      /// <author>Gert Driesen</author>
      /// <author>Rodrigo B. de Oliveira</author>
      /// <author>Douglas de la Torre</author>
      /// <author>Niall Daley</author>
      public class FileAppender : TextWriterAppender
      {
          #region LockingStream Inner Class
  
          /// <summary>
          /// Write only <see cref="Stream"/> that uses the <see cref="LockingModelBase"/> 
          /// to manage access to an underlying resource.
          /// </summary>
          protected sealed class LockingStream : Stream, IDisposable
          {
              /// <summary>
              /// Exception based on the LockState.
              /// </summary>
              public sealed class LockStateException : LogException
              {
                  /// <summary>
                  /// Constructor.
                  /// </summary>
                  /// <param name="message">Exception message.</param>
                  public LockStateException(string message)
                      : base(message)
                  {
                  }
              }
  
              private Stream m_realStream = null;
              private readonly LockingModelBase m_lockingModel = null;
              private int m_readTotal = -1;
              private int m_lockLevel = 0;
  
              /// <summary>
              /// The Lock level.
              /// </summary>
              public int LockLevel
              {
                  get { return m_lockLevel; }
              }
  
              /// <summary>
              /// Constructor.
              /// </summary>
              /// <param name="locking">The locking model.</param>
              /// <param name="lockLevel">The lock level.</param>
              public LockingStream(LockingModelBase locking, int lockLevel)
              {
                  if (locking == null)
                  {
                      throw new ArgumentException("Locking model may not be null", "locking");
                  }
                  m_lockingModel = locking;
  
                  m_lockLevel = lockLevel;
              }
  
              #region Override Implementation of Stream
  
              // Methods
              /// <summary>
              /// Begin read.
              /// </summary>
              /// <param name="buffer"></param>
              /// <param name="offset"></param>
              /// <param name="count"></param>
              /// <param name="callback"></param>
              /// <param name="state"></param>
              /// <returns></returns>
              public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
              {
                  AssertLocked();
                  IAsyncResult ret = m_realStream.BeginRead(buffer, offset, count, callback, state);
                  m_readTotal = EndRead(ret);
                  return ret;
              }
  
              /// <summary>
              /// True asynchronous writes are not supported, the implementation forces a synchronous write.
              /// </summary>
              public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
              {
                  AssertLocked();
                  IAsyncResult ret = m_realStream.BeginWrite(buffer, offset, count, callback, state);
                  EndWrite(ret);
                  return ret;
              }
  
              /// <summary>
              /// Close the log file.
              /// </summary>
              public override void Close()
              {
                  m_lockingModel.CloseFile();
              }
  
              /// <summary>
              /// End an asynchronous read.
              /// </summary>
              /// <param name="asyncResult"></param>
              /// <returns></returns>
              public override int EndRead(IAsyncResult asyncResult)
              {
                  AssertLocked();
                  return m_readTotal;
              }
              /// <summary>
              /// End an asychronous write.
              /// </summary>
              /// <param name="asyncResult"></param>
              public override void EndWrite(IAsyncResult asyncResult)
              {
                  //No-op, it has already been handled
              }
              /// <summary>
              /// Flush write data.
              /// </summary>
              public override void Flush()
              {
                  AssertLocked();
                  m_realStream.Flush();
              }
              /// <summary>
              /// Read from the stream.
              /// </summary>
              /// <param name="buffer"></param>
              /// <param name="offset"></param>
              /// <param name="count"></param>
              /// <returns></returns>
              public override int Read(byte[] buffer, int offset, int count)
              {
                  lock (this)
                  {
                      return m_realStream.Read(buffer, offset, count);
                  }
              }
              /// <summary>
              /// Read a byte from the stream.
              /// </summary>
              /// <returns></returns>
              public override int ReadByte()
              {
                  return m_realStream.ReadByte();
              }
              /// <summary>
              /// Seek in the stream.
              /// </summary>
              /// <param name="offset"></param>
              /// <param name="origin"></param>
              /// <returns></returns>
              public override long Seek(long offset, SeekOrigin origin)
              {
                  AssertLocked();
                  return m_realStream.Seek(offset, origin);
              }
              /// <summary>
              /// Set the length of the stream.
              /// </summary>
              /// <param name="value"></param>
              public override void SetLength(long value)
              {
                  AssertLocked();
                  m_realStream.SetLength(value);
              }
              /// <summary>
              /// Dispose the stream.
              /// </summary>
              void IDisposable.Dispose()
              {
                  Close();
              }
              /// <summary>
              /// Write to the stream.
              /// </summary>
              /// <param name="buffer"></param>
              /// <param name="offset"></param>
              /// <param name="count"></param>
              public override void Write(byte[] buffer, int offset, int count)
              {
                  AssertLocked();
                  m_realStream.Write(buffer, offset, count);
              }
              /// <summary>
              /// Write a byte to the stream.
              /// </summary>
              /// <param name="value"></param>
              public override void WriteByte(byte value)
              {
                  AssertLocked();
                  m_realStream.WriteByte(value);
              }
  
              // Properties
              /// <summary>
              /// Can the stream read?
              /// </summary>
              public override bool CanRead
              {
                  get { return false; }
              }
              /// <summary>
              /// Can the stream seek?
              /// </summary>
              public override bool CanSeek
              {
                  get
                  {
                      AssertLocked();
                      return m_realStream.CanSeek;
                  }
              }
              /// <summary>
              /// Can the stream write?
              /// </summary>
              public override bool CanWrite
              {
                  get
                  {
                      AssertLocked();
                      return m_realStream.CanWrite;
                  }
              }
              /// <summary>
              /// What is the length of the stream?
              /// </summary>
              public override long Length
              {
                  get
                  {
                      AssertLocked();
                      return m_realStream.Length;
                  }
              }
              /// <summary>
              /// what is the current position within the stream?
              /// </summary>
              public override long Position
              {
                  get
                  {
                      AssertLocked();
                      return m_realStream.Position;
                  }
                  set
                  {
                      AssertLocked();
                      m_realStream.Position = value;
                  }
              }
  
              #endregion Override Implementation of Stream
  
              #region Locking Methods
              /// <summary>
              /// Reopen the file.
              /// </summary>
              public void Reopen()
              {
                  if (m_realStream != null)
                  {
                      m_lockingModel.ReopenFile();
                      m_realStream = m_lockingModel.Stream;
                      m_realStream.Seek(0, SeekOrigin.End);
                  }
              }
  
              private void AssertLocked()
              {
                  lock (this)
                  {
                      if (!m_lockingModel.Locked)
                          throw new LockStateException("The file is not currently locked");
                  }
              }
              /// <summary>
              /// Acquire a lock on the file.
              /// </summary>
              /// <returns></returns>
              public bool AcquireLock()
              {
                  bool ret;
                  lock (this)
                  {
                      if (!m_lockingModel.Locked)
                      {
                          // If lock is already acquired, nop
                          if (m_lockingModel.AcquireLock())
                          {
                              m_lockLevel = 1;
  
                              m_realStream = m_lockingModel.Stream;
  
                              try
                              {
  								if (m_realStream.Position > m_realStream.Length) 
  								{
  									// if the file is rolled in another thread, our stream sees the updated stream length but the position IS NOT CHANGED
  									// any further attempts to set the position causes an exception because the current position is beyond the end of the
  									// file, so we must reopen the stream (which will put the cursor at the end of the file anyway)
  									Reopen();
  								}
  								else 
  								{
  									if (m_realStream.CanSeek)
  										m_realStream.Seek(0, SeekOrigin.End);
  								}
                              }
                              catch (Exception e)
                              {
                                  LogLog.Error(typeof(FileAppender),"FileAppender: INTERNAL ERROR.  Unable to see file: " + e.Message);
                              }
  
                              ret = true;
                          }
                          else
                              ret = false;
                      }
                      else
                      {
                          m_lockLevel++;
                          ret = true;
  
gt:                         if (m_realStream == null)