Author: dpsenner
Date: Sun Nov  1 16:29:57 2015
New Revision: 1711829

URL: http://svn.apache.org/viewvc?rev=1711829&view=rev
Log:
LOG4NET-484: fix object disposed exception

This is a modified version of the patch supplied by nn1436401 at gmail dot com.

Modified:
    logging/log4net/trunk/src/Appender/FileAppender.cs
    logging/log4net/trunk/tests/src/Appender/RollingFileAppenderTest.cs

Modified: logging/log4net/trunk/src/Appender/FileAppender.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/src/Appender/FileAppender.cs?rev=1711829&r1=1711828&r2=1711829&view=diff
==============================================================================
--- logging/log4net/trunk/src/Appender/FileAppender.cs (original)
+++ logging/log4net/trunk/src/Appender/FileAppender.cs Sun Nov  1 16:29:57 2015
@@ -1,1360 +1,1366 @@
-#region Apache License
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more 
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership. 
-// The ASF licenses this file to you under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with 
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#endregion
-
-using System;
-using System.IO;
-using System.Text;
-using System.Threading;
-using log4net.Util;
-using log4net.Layout;
-using log4net.Core;
-
-namespace log4net.Appender
-{
-#if !NETCF
-       /// <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.ExclusiveLock"/> 
-    /// is to obtain an exclusive write lock on the file until this appender 
is closed.
-    /// The alternative models only hold a
-    /// write lock while the appender is writing a logging event (<see 
cref="FileAppender.MinimalLock"/>)
-    /// or synchronize by using a named system wide Mutex (<see 
cref="FileAppender.InterProcessLock"/>).
-    /// </para>
-    /// <para>
-    /// All locking strategies have issues and you should seriously consider 
using a different strategy that
-    /// avoids having multiple processes logging to the same file.
-    /// </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>
-#else
-       /// <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.ExclusiveLock"/> 
-       /// is to obtain an exclusive write lock on the file until this 
appender is closed.
-       /// The alternative model only holds a
-    /// write lock while the appender is writing a logging event (<see 
cref="FileAppender.MinimalLock"/>).
-       /// </para>
-    /// <para>
-    /// All locking strategies have issues and you should seriously consider 
using a different strategy that
-    /// avoids having multiple processes logging to the same file.
-    /// </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>
-#endif
-    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>
-               private sealed class LockingStream : Stream, IDisposable
-               {
-                       public sealed class LockStateException : LogException
-                       {
-                               public LockStateException(string message): 
base(message)
-                               {
-                               }
-                       }
-
-                       private Stream m_realStream=null;
-                       private LockingModelBase m_lockingModel=null;
-                       private int m_readTotal=-1;
-                       private int m_lockLevel=0;
-
-                       public LockingStream(LockingModelBase locking) : base()
-                       {
-                               if (locking==null)
-                               {
-                                       throw new ArgumentException("Locking 
model may not be null","locking");
-                               }
-                               m_lockingModel=locking;
-                       }
-
-                       #region Override Implementation of Stream
-
-                       // Methods
-                       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;
-                       }
-
-                       public override void Close() 
-                       {
-                               m_lockingModel.CloseFile();
-                       }
-
-                       public override int EndRead(IAsyncResult asyncResult) 
-                       {
-                               AssertLocked();
-                               return m_readTotal;
-                       }
-                       public override void EndWrite(IAsyncResult asyncResult) 
-                       {
-                               //No-op, it has already been handled
-                       }
-                       public override void Flush() 
-                       {
-                               AssertLocked();
-                               m_realStream.Flush();
-                       }
-                       public override int Read(byte[] buffer, int offset, int 
count) 
-                       {
-                               return m_realStream.Read(buffer,offset,count);
-                       }
-                       public override int ReadByte() 
-                       {
-                               return m_realStream.ReadByte();
-                       }
-                       public override long Seek(long offset, SeekOrigin 
origin) 
-                       {
-                               AssertLocked();
-                               return m_realStream.Seek(offset,origin);
-                       }
-                       public override void SetLength(long value) 
-                       {
-                               AssertLocked();
-                               m_realStream.SetLength(value);
-                       }
-                       void IDisposable.Dispose() 
-                       {
-                               Close();
-                       }
-                       public override void Write(byte[] buffer, int offset, 
int count) 
-                       {
-                               AssertLocked();
-                               m_realStream.Write(buffer,offset,count);
-                       }
-                       public override void WriteByte(byte value) 
-                       {
-                               AssertLocked();
-                               m_realStream.WriteByte(value);
-                       }
-
-                       // Properties
-                       public override bool CanRead 
-                       { 
-                               get { return false; } 
-                       }
-                       public override bool CanSeek 
-                       { 
-                               get 
-                               {
-                                       AssertLocked();
-                                       return m_realStream.CanSeek;
-                               } 
-                       }
-                       public override bool CanWrite 
-                       { 
-                               get 
-                               {
-                                       AssertLocked();
-                                       return m_realStream.CanWrite;
-                               } 
-                       }
-                       public override long Length 
-                       { 
-                               get 
-                               {
-                                       AssertLocked();
-                                       return m_realStream.Length;
-                               } 
-                       }
-                       public override long Position 
-                       { 
-                               get 
-                               {
-                                       AssertLocked();
-                                       return m_realStream.Position;
-                               } 
-                               set 
-                               {
-                                       AssertLocked();
-                                       m_realStream.Position=value;
-                               } 
-                       }
-
-                       #endregion Override Implementation of Stream
-
-                       #region Locking Methods
-
-                       private void AssertLocked()
-                       {
-                               if (m_realStream == null)
-                               {
-                                       throw new LockStateException("The file 
is not currently locked");
-                               }
-                       }
-
-                       public bool AcquireLock()
-                       {
-                               bool ret=false;
-                               lock(this)
-                               {
-                                       if (m_lockLevel==0)
-                                       {
-                                               // If lock is already acquired, 
nop
-                                               
m_realStream=m_lockingModel.AcquireLock();
-                                       }
-                                       if (m_realStream!=null)
-                                       {
-                                               m_lockLevel++;
-                                               ret=true;
-                                       }
-                               }
-                               return ret;
-                       }
-
-                       public void ReleaseLock()
-                       {
-                               lock(this)
-                               {
-                                       m_lockLevel--;
-                                       if (m_lockLevel==0)
-                                       {
-                                               // If already unlocked, nop
-                                               m_lockingModel.ReleaseLock();
-                                               m_realStream=null;
-                                       }
-                               }
-                       }
-
-                       #endregion Locking Methods
-               }
-
-               #endregion LockingStream Inner Class
-
-               #region Locking Models
-
-               /// <summary>
-               /// Locking model base class
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Base class for the locking models available to the <see 
cref="FileAppender"/> derived loggers.
-               /// </para>
-               /// </remarks>
-               public abstract class LockingModelBase
-               {
-                       private FileAppender m_appender=null;
-
-                       /// <summary>
-                       /// Open the output file
-                       /// </summary>
-                       /// <param name="filename">The filename to use</param>
-                       /// <param name="append">Whether to append to the file, 
or overwrite</param>
-                       /// <param name="encoding">The encoding to use</param>
-                       /// <remarks>
-                       /// <para>
-                       /// Open the file specified and prepare for logging. 
-                       /// No writes will be made until <see 
cref="AcquireLock"/> is called.
-                       /// Must be called before any calls to <see 
cref="AcquireLock"/>,
-                       /// <see cref="ReleaseLock"/> and <see 
cref="CloseFile"/>.
-                       /// </para>
-                       /// </remarks>
-                       public abstract void OpenFile(string filename, bool 
append,Encoding encoding);
-
-                       /// <summary>
-                       /// Close the file
-                       /// </summary>
-                       /// <remarks>
-                       /// <para>
-                       /// Close the file. No further writes will be made.
-                       /// </para>
-                       /// </remarks>
-                       public abstract void CloseFile();
-
-                       /// <summary>
-                       /// Acquire the lock on the file
-                       /// </summary>
-                       /// <returns>A stream that is ready to be written 
to.</returns>
-                       /// <remarks>
-                       /// <para>
-                       /// Acquire the lock on the file in preparation for 
writing to it. 
-                       /// Return a stream pointing to the file. <see 
cref="ReleaseLock"/>
-                       /// must be called to release the lock on the output 
file.
-                       /// </para>
-                       /// </remarks>
-                       public abstract Stream AcquireLock();
-
-                       /// <summary>
-                       /// Release the lock on the file
-                       /// </summary>
-                       /// <remarks>
-                       /// <para>
-                       /// Release the lock on the file. No further writes 
will be made to the 
-                       /// stream until <see cref="AcquireLock"/> is called 
again.
-                       /// </para>
-                       /// </remarks>
-                       public abstract void ReleaseLock();
-
-                       /// <summary>
-                       /// Gets or sets the <see cref="FileAppender"/> for 
this LockingModel
-                       /// </summary>
-                       /// <value>
-                       /// The <see cref="FileAppender"/> for this LockingModel
-                       /// </value>
-                       /// <remarks>
-                       /// <para>
-                       /// The file appender this locking model is attached to 
and working on
-                       /// behalf of.
-                       /// </para>
-                       /// <para>
-                       /// The file appender is used to locate the security 
context and the error handler to use.
-                       /// </para>
-                       /// <para>
-                       /// The value of this property will be set before <see 
cref="OpenFile"/> is
-                       /// called.
-                       /// </para>
-                       /// </remarks>
-                       public FileAppender CurrentAppender
-                       {
-                               get { return m_appender; }
-                               set { m_appender = value; }
-                       }
-
-            /// <summary>
-            /// Helper method that creates a FileStream under 
CurrentAppender's SecurityContext.
-            /// </summary>
-            /// <remarks>
-            /// <para>
-            /// Typically called during OpenFile or AcquireLock. 
-            /// </para>
-            /// <para>
-            /// If the directory portion of the <paramref name="filename"/> 
does not exist, it is created
-            /// via Directory.CreateDirecctory.
-            /// </para>
-            /// </remarks>
-            /// <param name="filename"></param>
-            /// <param name="append"></param>
-            /// <param name="fileShare"></param>
-            /// <returns></returns>
-            protected Stream CreateStream(string filename, bool append, 
FileShare fileShare)
-            {
-                using (CurrentAppender.SecurityContext.Impersonate(this))
-                {
-                    // Ensure that the directory structure exists
-                    string directoryFullName = Path.GetDirectoryName(filename);
-
-                    // Only create the directory if it does not exist
-                    // doing this check here resolves some permissions failures
-                    if (!Directory.Exists(directoryFullName))
-                    {
-                        Directory.CreateDirectory(directoryFullName);
-                    }
-
-                    FileMode fileOpenMode = append ? FileMode.Append : 
FileMode.Create;
-                    return new FileStream(filename, fileOpenMode, 
FileAccess.Write, fileShare);
-                }
-            }
-
-            /// <summary>
-            /// Helper method to close <paramref name="stream"/> under 
CurrentAppender's SecurityContext.
-            /// </summary>
-            /// <remarks>
-            /// Does not set <paramref name="stream"/> to null.
-            /// </remarks>
-            /// <param name="stream"></param>
-            protected void CloseStream(Stream stream)
-            {
-                using (CurrentAppender.SecurityContext.Impersonate(this))
-                {
-                    stream.Close();
-                }
-           }
-               }
-
-               /// <summary>
-               /// Hold an exclusive lock on the output file
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Open the file once for writing and hold it open until <see 
cref="CloseFile"/> is called. 
-               /// Maintains an exclusive lock on the file during this time.
-               /// </para>
-               /// </remarks>
-               public class ExclusiveLock : LockingModelBase
-               {
-                       private Stream m_stream = null;
-
-                       /// <summary>
-                       /// Open the file specified and prepare for logging.
-                       /// </summary>
-                       /// <param name="filename">The filename to use</param>
-                       /// <param name="append">Whether to append to the file, 
or overwrite</param>
-                       /// <param name="encoding">The encoding to use</param>
-                       /// <remarks>
-                       /// <para>
-                       /// Open the file specified and prepare for logging. 
-                       /// No writes will be made until <see 
cref="AcquireLock"/> is called.
-                       /// Must be called before any calls to <see 
cref="AcquireLock"/>,
-                       /// <see cref="ReleaseLock"/> and <see 
cref="CloseFile"/>.
-                       /// </para>
-                       /// </remarks>
-                       public override void OpenFile(string filename, bool 
append,Encoding encoding)
-                       {
-                               try
-                               {
-                    m_stream = CreateStream(filename, append, FileShare.Read);
-                               }
-                               catch (Exception e1)
-                               {
-                                       
CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file 
"+filename+". "+e1.Message);
-                               }
-                       }
-
-                       /// <summary>
-                       /// Close the file
-                       /// </summary>
-                       /// <remarks>
-                       /// <para>
-                       /// Close the file. No further writes will be made.
-                       /// </para>
-                       /// </remarks>
-                       public override void CloseFile()
-                       {
-                CloseStream(m_stream);
-                m_stream = null;
-                       }
-
-                       /// <summary>
-                       /// Acquire the lock on the file
-                       /// </summary>
-                       /// <returns>A stream that is ready to be written 
to.</returns>
-                       /// <remarks>
-                       /// <para>
-                       /// Does nothing. The lock is already taken
-                       /// </para>
-                       /// </remarks>
-                       public override Stream AcquireLock()
-                       {
-                               return m_stream;
-                       }
-
-                       /// <summary>
-                       /// Release the lock on the file
-                       /// </summary>
-                       /// <remarks>
-                       /// <para>
-                       /// Does nothing. The lock will be released when the 
file is closed.
-                       /// </para>
-                       /// </remarks>
-                       public override void ReleaseLock()
-                       {
-                               //NOP
-                       }
-               }
-
-               /// <summary>
-               /// Acquires the file lock for each write
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Opens the file once for each <see cref="AcquireLock"/>/<see 
cref="ReleaseLock"/> cycle, 
-               /// thus holding the lock for the minimal amount of time. This 
method of locking
-               /// is considerably slower than <see 
cref="FileAppender.ExclusiveLock"/> but allows 
-               /// other processes to move/delete the log file whilst logging 
continues.
-               /// </para>
-               /// </remarks>
-               public class MinimalLock : LockingModelBase
-               {
-                       private string m_filename;
-                       private bool m_append;
-                       private Stream m_stream=null;
-
-                       /// <summary>
-                       /// Prepares to open the file when the first message is 
logged.
-                       /// </summary>
-                       /// <param name="filename">The filename to use</param>
-                       /// <param name="append">Whether to append to the file, 
or overwrite</param>
-                       /// <param name="encoding">The encoding to use</param>
-                       /// <remarks>
-                       /// <para>
-                       /// Open the file specified and prepare for logging. 
-                       /// No writes will be made until <see 
cref="AcquireLock"/> is called.
-                       /// Must be called before any calls to <see 
cref="AcquireLock"/>,
-                       /// <see cref="ReleaseLock"/> and <see 
cref="CloseFile"/>.
-                       /// </para>
-                       /// </remarks>
-                       public override void OpenFile(string filename, bool 
append, Encoding encoding)
-                       {
-                               m_filename=filename;
-                               m_append=append;
-                       }
-
-                       /// <summary>
-                       /// Close the file
-                       /// </summary>
-                       /// <remarks>
-                       /// <para>
-                       /// Close the file. No further writes will be made.
-                       /// </para>
-                       /// </remarks>
-                       public override void CloseFile()
-                       {
-                               // NOP
-                       }
-
-                       /// <summary>
-                       /// Acquire the lock on the file
-                       /// </summary>
-                       /// <returns>A stream that is ready to be written 
to.</returns>
-                       /// <remarks>
-                       /// <para>
-                       /// Acquire the lock on the file in preparation for 
writing to it. 
-                       /// Return a stream pointing to the file. <see 
cref="ReleaseLock"/>
-                       /// must be called to release the lock on the output 
file.
-                       /// </para>
-                       /// </remarks>
-                       public override Stream AcquireLock()
-                       {
-                               if (m_stream==null)
-                               {
-                                       try
-                                       {
-                        m_stream = CreateStream(m_filename, m_append, 
FileShare.Read);
-                        m_append = true;
-                                       }
-                                       catch (Exception e1)
-                                       {
-                                               
CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file 
"+m_filename+". "+e1.Message);
-                                       }
-                               }
-                               return m_stream;
-                       }
-
-                       /// <summary>
-                       /// Release the lock on the file
-                       /// </summary>
-                       /// <remarks>
-                       /// <para>
-                       /// Release the lock on the file. No further writes 
will be made to the 
-                       /// stream until <see cref="AcquireLock"/> is called 
again.
-                       /// </para>
-                       /// </remarks>
-                       public override void ReleaseLock()
-                       {
-                CloseStream(m_stream);
-                m_stream = null;
-                       }
-               }
-
-#if !NETCF
-        /// <summary>
-        /// Provides cross-process file locking.
-        /// </summary>
-        /// <author>Ron Grabowski</author>
-        /// <author>Steve Wranovsky</author>
-        public class InterProcessLock : LockingModelBase
-        {
-            private Mutex m_mutex = null;
-            private bool m_mutexClosed = false;
-            private Stream m_stream = null;
-
-            /// <summary>
-            /// Open the file specified and prepare for logging.
-            /// </summary>
-            /// <param name="filename">The filename to use</param>
-            /// <param name="append">Whether to append to the file, or 
overwrite</param>
-            /// <param name="encoding">The encoding to use</param>
-            /// <remarks>
-            /// <para>
-            /// Open the file specified and prepare for logging. 
-            /// No writes will be made until <see cref="AcquireLock"/> is 
called.
-            /// Must be called before any calls to <see cref="AcquireLock"/>,
-            /// -<see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
-            /// </para>
-            /// </remarks>
-#if NET_4_0 || MONO_4_0
-            [System.Security.SecuritySafeCritical]
-#endif
-            public override void OpenFile(string filename, bool append, 
Encoding encoding)
-            {
-                try
-                {
-                    m_stream = CreateStream(filename, append, 
FileShare.ReadWrite);
-
-                    string mutextFriendlyFilename = filename
-                            .Replace("\\", "_")
-                            .Replace(":", "_")
-                            .Replace("/", "_");
-
-                    m_mutex = new Mutex(false, mutextFriendlyFilename); 
-                    m_mutexClosed = false;
-                }
-                catch (Exception e1)
-                {
-                    CurrentAppender.ErrorHandler.Error("Unable to acquire lock 
on file " + filename + ". " + e1.Message);
-                }
-            }
-
-            /// <summary>
-            /// Close the file
-            /// </summary>
-            /// <remarks>
-            /// <para>
-            /// Close the file. No further writes will be made.
-            /// </para>
-            /// </remarks>
-            public override void CloseFile()
-            {
-                try {
-                    CloseStream(m_stream);
-                    m_stream = null;
-                }
-                finally {
-                    m_mutex.ReleaseMutex();
-                    m_mutex.Close();
-                    m_mutexClosed = true;
-                }
-            }
-
-            /// <summary>
-            /// Acquire the lock on the file
-            /// </summary>
-            /// <returns>A stream that is ready to be written to.</returns>
-            /// <remarks>
-            /// <para>
-            /// Does nothing. The lock is already taken
-            /// </para>
-            /// </remarks>
-            public override Stream AcquireLock()
-            {
-                if (m_mutex != null) {
-                    // TODO: add timeout?
-                    m_mutex.WaitOne();
-
-                    // should always be true (and fast) for FileStream
-                    if (m_stream.CanSeek) {
-                        m_stream.Seek(0, SeekOrigin.End);
-                    }
-                }
-
-                return m_stream;
-            }
-
-            /// <summary>
-            /// 
-            /// </summary>
-            public override void ReleaseLock()
-            {
-                if (m_mutexClosed == false && m_mutex != null)
-                {
-                    m_mutex.ReleaseMutex();
-                }
-            }
-        }
-#endif
-
-               #endregion Locking Models
-
-               #region Public Instance Constructors
-
-               /// <summary>
-               /// Default constructor
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Default constructor
-               /// </para>
-               /// </remarks>
-               public FileAppender()
-               {
-               }
-
-               /// <summary>
-               /// Construct a new appender using the layout, file and append 
mode.
-               /// </summary>
-               /// <param name="layout">the layout to use with this 
appender</param>
-               /// <param name="filename">the full path to the file to write 
to</param>
-               /// <param name="append">flag to indicate if the file should be 
appended to</param>
-               /// <remarks>
-               /// <para>
-               /// Obsolete constructor.
-               /// </para>
-               /// </remarks>
-               [Obsolete("Instead use the default constructor and set the 
Layout, File & AppendToFile properties")]
-               public FileAppender(ILayout layout, string filename, bool 
append) 
-               {
-                       Layout = layout;
-                       File = filename;
-                       AppendToFile = append;
-                       ActivateOptions();
-               }
-
-               /// <summary>
-               /// Construct a new appender using the layout and file 
specified.
-               /// The file will be appended to.
-               /// </summary>
-               /// <param name="layout">the layout to use with this 
appender</param>
-               /// <param name="filename">the full path to the file to write 
to</param>
-               /// <remarks>
-               /// <para>
-               /// Obsolete constructor.
-               /// </para>
-               /// </remarks>
-               [Obsolete("Instead use the default constructor and set the 
Layout & File properties")]
-               public FileAppender(ILayout layout, string filename) : 
this(layout, filename, true)
-               {
-               }
-
-               #endregion Public Instance Constructors
-
-               #region Public Instance Properties
-
-               /// <summary>
-               /// Gets or sets the path to the file that logging will be 
written to.
-               /// </summary>
-               /// <value>
-               /// The path to the file that logging will be written to.
-               /// </value>
-               /// <remarks>
-               /// <para>
-               /// If the path is relative it is taken as relative from 
-               /// the application base directory.
-               /// </para>
-               /// </remarks>
-               virtual public string File
-               {
-                       get { return m_fileName; }
-                       set { m_fileName = value; }
-               }
-
-               /// <summary>
-               /// Gets or sets a flag that indicates whether the file should 
be
-               /// appended to or overwritten.
-               /// </summary>
-               /// <value>
-               /// Indicates whether the file should be appended to or 
overwritten.
-               /// </value>
-               /// <remarks>
-               /// <para>
-               /// If the value is set to false then the file will be 
overwritten, if 
-               /// it is set to true then the file will be appended to.
-               /// </para>
-               /// The default value is true.
-               /// </remarks>
-               public bool AppendToFile
-               {
-                       get { return m_appendToFile; }
-                       set { m_appendToFile = value; }
-               }
-
-               /// <summary>
-               /// Gets or sets <see cref="Encoding"/> used to write to the 
file.
-               /// </summary>
-               /// <value>
-               /// The <see cref="Encoding"/> used to write to the file.
-               /// </value>
-               /// <remarks>
-               /// <para>
-               /// The default encoding set is <see 
cref="System.Text.Encoding.Default"/>
-               /// which is the encoding for the system's current ANSI code 
page.
-               /// </para>
-               /// </remarks>
-               public Encoding Encoding
-               {
-                       get { return m_encoding; }
-                       set { m_encoding = value; }
-               }
-
-               /// <summary>
-               /// Gets or sets the <see cref="SecurityContext"/> used to 
write to the file.
-               /// </summary>
-               /// <value>
-               /// The <see cref="SecurityContext"/> used to write to the file.
-               /// </value>
-               /// <remarks>
-               /// <para>
-               /// Unless a <see cref="SecurityContext"/> specified here for 
this appender
-               /// the <see cref="SecurityContextProvider.DefaultProvider"/> 
is queried for the
-               /// security context to use. The default behavior is to use the 
security context
-               /// of the current thread.
-               /// </para>
-               /// </remarks>
-               public SecurityContext SecurityContext 
-               {
-                       get { return m_securityContext; }
-                       set { m_securityContext = value; }
-               }
-
-#if NETCF
-               /// <summary>
-               /// Gets or sets the <see cref="FileAppender.LockingModel"/> 
used to handle locking of the file.
-               /// </summary>
-               /// <value>
-               /// The <see cref="FileAppender.LockingModel"/> used to lock 
the file.
-               /// </value>
-               /// <remarks>
-               /// <para>
-               /// Gets or sets the <see cref="FileAppender.LockingModel"/> 
used to handle locking of the file.
-               /// </para>
-               /// <para>
-        /// There are two built in locking models, <see 
cref="FileAppender.ExclusiveLock"/> and <see cref="FileAppender.MinimalLock"/>.
-               /// The first locks the file from the start of logging to the 
end, the 
-               /// second locks only for the minimal amount of time when 
logging each message
-        /// and the last synchronizes processes using a named system wide 
Mutex.
-               /// </para>
-               /// <para>
-               /// The default locking model is the <see 
cref="FileAppender.ExclusiveLock"/>.
-               /// </para>
-               /// </remarks>
-#else
-        /// <summary>
-               /// Gets or sets the <see cref="FileAppender.LockingModel"/> 
used to handle locking of the file.
-               /// </summary>
-               /// <value>
-               /// The <see cref="FileAppender.LockingModel"/> used to lock 
the file.
-               /// </value>
-               /// <remarks>
-               /// <para>
-               /// Gets or sets the <see cref="FileAppender.LockingModel"/> 
used to handle locking of the file.
-               /// </para>
-               /// <para>
-        /// There are three built in locking models, <see 
cref="FileAppender.ExclusiveLock"/>, <see cref="FileAppender.MinimalLock"/> and 
<see cref="FileAppender.InterProcessLock"/> .
-               /// The first locks the file from the start of logging to the 
end, the 
-               /// second locks only for the minimal amount of time when 
logging each message
-        /// and the last synchronizes processes using a named system wide 
Mutex.
-               /// </para>
-               /// <para>
-               /// The default locking model is the <see 
cref="FileAppender.ExclusiveLock"/>.
-               /// </para>
-               /// </remarks>
-#endif
-               public FileAppender.LockingModelBase LockingModel
-               {
-                       get { return m_lockingModel; }
-                       set { m_lockingModel = value; }
-               }
-
-               #endregion Public Instance Properties
-
-               #region Override implementation of AppenderSkeleton
-
-               /// <summary>
-               /// Activate the options on the file appender. 
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// This is part of the <see cref="IOptionHandler"/> delayed 
object
-               /// activation scheme. The <see cref="ActivateOptions"/> method 
must 
-               /// be called on this object after the configuration properties 
have
-               /// been set. Until <see cref="ActivateOptions"/> is called this
-               /// object is in an undefined state and must not be used. 
-               /// </para>
-               /// <para>
-               /// If any of the configuration properties are modified then 
-               /// <see cref="ActivateOptions"/> must be called again.
-               /// </para>
-               /// <para>
-               /// This will cause the file to be opened.
-               /// </para>
-               /// </remarks>
-               override public void ActivateOptions() 
-               {       
-                       base.ActivateOptions();
-
-                       if (m_securityContext == null)
-                       {
-                               m_securityContext = 
SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
-                       }
-
-                       if (m_lockingModel == null)
-                       {
-                               m_lockingModel = new 
FileAppender.ExclusiveLock();
-                       }
-
-                       m_lockingModel.CurrentAppender=this;
-                       
-                       if (m_fileName != null) 
-                       {
-                               using(SecurityContext.Impersonate(this))
-                               {
-                                       m_fileName = 
ConvertToFullPath(m_fileName.Trim());
-                               }
-                               SafeOpenFile(m_fileName, m_appendToFile);
-                       } 
-                       else 
-                       {
-                               LogLog.Warn(declaringType, "FileAppender: File 
option not set for appender ["+Name+"].");
-                               LogLog.Warn(declaringType, "FileAppender: Are 
you using FileAppender instead of ConsoleAppender?");
-                       }
-               }
-
-               #endregion Override implementation of AppenderSkeleton
-
-               #region Override implementation of TextWriterAppender
-
-               /// <summary>
-               /// Closes any previously opened file and calls the parent's 
<see cref="TextWriterAppender.Reset"/>.
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Resets the filename and the file stream.
-               /// </para>
-               /// </remarks>
-               override protected void Reset() 
-               {
-                       base.Reset();
-                       m_fileName = null;
-               }
-
-               /// <summary>
-               /// Called to initialize the file writer
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Will be called for each logged message until the file is
-               /// successfully opened.
-               /// </para>
-               /// </remarks>
-               override protected void PrepareWriter()
-               {
-                       SafeOpenFile(m_fileName, m_appendToFile);
-               }
-
-               /// <summary>
-               /// This method is called by the <see 
cref="M:AppenderSkeleton.DoAppend(LoggingEvent)"/>
-               /// method. 
-               /// </summary>
-               /// <param name="loggingEvent">The event to log.</param>
-               /// <remarks>
-               /// <para>
-               /// Writes a log statement to the output stream if the output 
stream exists 
-               /// and is writable.  
-               /// </para>
-               /// <para>
-               /// The format of the output will depend on the appender's 
layout.
-               /// </para>
-               /// </remarks>
-               override protected void Append(LoggingEvent loggingEvent) 
-               {
-                       if (m_stream.AcquireLock())
-                       {
-                               try
-                               {
-                                       base.Append(loggingEvent);
-                               }
-                               finally
-                               {
-                                       m_stream.ReleaseLock();
-                               }
-                       }
-               }
-
-               /// <summary>
-               /// This method is called by the <see 
cref="M:AppenderSkeleton.DoAppend(LoggingEvent[])"/>
-               /// method. 
-               /// </summary>
-               /// <param name="loggingEvents">The array of events to 
log.</param>
-               /// <remarks>
-               /// <para>
-               /// Acquires the output file locks once before writing all the 
events to
-               /// the stream.
-               /// </para>
-               /// </remarks>
-               override protected void Append(LoggingEvent[] loggingEvents) 
-               {
-                       if (m_stream.AcquireLock())
-                       {
-                               try
-                               {
-                                       base.Append(loggingEvents);
-                               }
-                               finally
-                               {
-                                       m_stream.ReleaseLock();
-                               }
-                       }
-               }
-
-               /// <summary>
-               /// Writes a footer as produced by the embedded layout's <see 
cref="ILayout.Footer"/> property.
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Writes a footer as produced by the embedded layout's <see 
cref="ILayout.Footer"/> property.
-               /// </para>
-               /// </remarks>
-               protected override void WriteFooter() 
-               {
-                       if (m_stream!=null)
-                       {
-                               //WriteFooter can be called even before a file 
is opened
-                               m_stream.AcquireLock();
-                               try
-                               {
-                                       base.WriteFooter();
-                               }
-                               finally
-                               {
-                                       m_stream.ReleaseLock();
-                               }
-                       }
-               }
-
-               /// <summary>
-               /// Writes a header produced by the embedded layout's <see 
cref="ILayout.Header"/> property.
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Writes a header produced by the embedded layout's <see 
cref="ILayout.Header"/> property.
-               /// </para>
-               /// </remarks>
-               protected override void WriteHeader() 
-               {
-                       if (m_stream!=null)
-                       {
-                               if (m_stream.AcquireLock())
-                               {
-                                       try
-                                       {
-                                               base.WriteHeader();
-                                       }
-                                       finally
-                                       {
-                                               m_stream.ReleaseLock();
-                                       }
-                               }
-                       }
-               }
-
-               /// <summary>
-               /// Closes the underlying <see cref="TextWriter"/>.
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Closes the underlying <see cref="TextWriter"/>.
-               /// </para>
-               /// </remarks>
-               protected override void CloseWriter() 
-               {
-                       if (m_stream!=null)
-                       {
-                               m_stream.AcquireLock();
-                               try
-                               {
-                                       base.CloseWriter();
-                               }
-                               finally
-                               {
-                                       m_stream.ReleaseLock();
-                               }
-                       }
-               }
-
-               #endregion Override implementation of TextWriterAppender
-
-               #region Public Instance Methods
-
-               /// <summary>
-               /// Closes the previously opened file.
-               /// </summary>
-               /// <remarks>
-               /// <para>
-               /// Writes the <see cref="ILayout.Footer"/> to the file and then
-               /// closes the file.
-               /// </para>
-               /// </remarks>
-               protected void CloseFile() 
-               {
-                       WriteFooterAndCloseWriter();
-               }
-
-               #endregion Public Instance Methods
-
-               #region Protected Instance Methods
-
-               /// <summary>
-               /// Sets and <i>opens</i> the file where the log output will 
go. The specified file must be writable.
-               /// </summary>
-               /// <param name="fileName">The path to the log file. Must be a 
fully qualified path.</param>
-               /// <param name="append">If true will append to fileName. 
Otherwise will truncate fileName</param>
-               /// <remarks>
-               /// <para>
-               /// Calls <see cref="OpenFile"/> but guarantees not to throw an 
exception.
-               /// Errors are passed to the <see 
cref="TextWriterAppender.ErrorHandler"/>.
-               /// </para>
-               /// </remarks>
-               virtual protected void SafeOpenFile(string fileName, bool 
append)
-               {
-                       try 
-                       {
-                               OpenFile(fileName, append);
-                       }
-                       catch(Exception e) 
-                       {
-                               
ErrorHandler.Error("OpenFile("+fileName+","+append+") call failed.", e, 
ErrorCode.FileOpenFailure);
-                       }
-               }
-
-               /// <summary>
-               /// Sets and <i>opens</i> the file where the log output will 
go. The specified file must be writable.
-               /// </summary>
-               /// <param name="fileName">The path to the log file. Must be a 
fully qualified path.</param>
-               /// <param name="append">If true will append to fileName. 
Otherwise will truncate fileName</param>
-               /// <remarks>
-               /// <para>
-               /// If there was already an opened file, then the previous file
-               /// is closed first.
-               /// </para>
-               /// <para>
-               /// This method will ensure that the directory structure
-               /// for the <paramref name="fileName"/> specified exists.
-               /// </para>
-               /// </remarks>
-               virtual protected void OpenFile(string fileName, bool append)
-               {
-                       if (LogLog.IsErrorEnabled)
-                       {
-                               // Internal check that the fileName passed in 
is a rooted path
-                               bool isPathRooted = false;
-                               using(SecurityContext.Impersonate(this))
-                               {
-                                       isPathRooted = 
Path.IsPathRooted(fileName);
-                               }
-                               if (!isPathRooted)
-                               {
-                                       LogLog.Error(declaringType, "INTERNAL 
ERROR. OpenFile("+fileName+"): File name is not fully qualified.");
-                               }
-                       }
-
-                       lock(this)
-                       {
-                               Reset();
-
-                               LogLog.Debug(declaringType, "Opening file for 
writing ["+fileName+"] append ["+append+"]");
-
-                               // Save these for later, allowing retries if 
file open fails
-                               m_fileName = fileName;
-                               m_appendToFile = append;
-
-                               LockingModel.CurrentAppender=this;
-                               
LockingModel.OpenFile(fileName,append,m_encoding);
-                               m_stream=new LockingStream(LockingModel);
-
-                               if (m_stream != null)
-                               {
-                                       m_stream.AcquireLock();
-                                       try
-                                       {
-                                               SetQWForFiles(new 
StreamWriter(m_stream, m_encoding));
-                                       }
-                                       finally
-                                       {
-                                               m_stream.ReleaseLock();
-                                       }
-                               }
-
-                               WriteHeader();
-                       }
-               }
-
-               /// <summary>
-               /// Sets the quiet writer used for file output
-               /// </summary>
-               /// <param name="fileStream">the file stream that has been 
opened for writing</param>
-               /// <remarks>
-               /// <para>
-               /// This implementation of <see 
cref="M:SetQWForFiles(Stream)"/> creates a <see cref="StreamWriter"/>
-               /// over the <paramref name="fileStream"/> and passes it to the 
-               /// <see cref="M:SetQWForFiles(TextWriter)"/> method.
-               /// </para>
-               /// <para>
-               /// This method can be overridden by sub classes that want to 
wrap the
-               /// <see cref="Stream"/> in some way, for example to encrypt 
the output
-               /// data using a 
<c>System.Security.Cryptography.CryptoStream</c>.
-               /// </para>
-               /// </remarks>
-               virtual protected void SetQWForFiles(Stream fileStream) 
-               {
-                       SetQWForFiles(new StreamWriter(fileStream, m_encoding));
-               }
-
-               /// <summary>
-               /// Sets the quiet writer being used.
-               /// </summary>
-               /// <param name="writer">the writer over the file stream that 
has been opened for writing</param>
-               /// <remarks>
-               /// <para>
-               /// This method can be overridden by sub classes that want to
-               /// wrap the <see cref="TextWriter"/> in some way.
-               /// </para>
-               /// </remarks>
-               virtual protected void SetQWForFiles(TextWriter writer) 
-               {
-                       QuietWriter = new QuietTextWriter(writer, ErrorHandler);
-               }
-
-               #endregion Protected Instance Methods
-
-               #region Protected Static Methods
-
-               /// <summary>
-               /// Convert a path into a fully qualified path.
-               /// </summary>
-               /// <param name="path">The path to convert.</param>
-               /// <returns>The fully qualified path.</returns>
-               /// <remarks>
-               /// <para>
-               /// Converts the path specified to a fully
-               /// qualified path. If the path is relative it is
-               /// taken as relative from the application base 
-               /// directory.
-               /// </para>
-               /// </remarks>
-               protected static string ConvertToFullPath(string path)
-               {
-                       return SystemInfo.ConvertToFullPath(path);
-               }
-
-               #endregion Protected Static Methods
-
-               #region Private Instance Fields
-
-               /// <summary>
-               /// Flag to indicate if we should append to the file
-               /// or overwrite the file. The default is to append.
-               /// </summary>
-               private bool m_appendToFile = true;
-
-               /// <summary>
-               /// The name of the log file.
-               /// </summary>
-               private string m_fileName = null;
-
-               /// <summary>
-               /// The encoding to use for the file stream.
-               /// </summary>
-               private Encoding m_encoding = Encoding.Default;
-
-               /// <summary>
-               /// The security context to use for privileged calls
-               /// </summary>
-               private SecurityContext m_securityContext;
-
-               /// <summary>
-               /// The stream to log to. Has added locking semantics
-               /// </summary>
-               private FileAppender.LockingStream m_stream = null;
-
-               /// <summary>
-               /// The locking model to use
-               /// </summary>
-               private FileAppender.LockingModelBase m_lockingModel = new 
FileAppender.ExclusiveLock();
-
-               #endregion Private Instance Fields
-
-           #region Private Static Fields
-
-           /// <summary>
-           /// The fully qualified type of the FileAppender class.
-           /// </summary>
-           /// <remarks>
-           /// Used by the internal logger to record the Type of the
-           /// log message.
-           /// </remarks>
-           private readonly static Type declaringType = typeof(FileAppender);
-
-           #endregion Private Static Fields
-       }
-}
+#region Apache License
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more 
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership. 
+// The ASF licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#endregion
+
+using System;
+using System.IO;
+using System.Text;
+using System.Threading;
+using log4net.Util;
+using log4net.Layout;
+using log4net.Core;
+
+namespace log4net.Appender
+{
+#if !NETCF
+       /// <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.ExclusiveLock"/> 
+    /// is to obtain an exclusive write lock on the file until this appender 
is closed.
+    /// The alternative models only hold a
+    /// write lock while the appender is writing a logging event (<see 
cref="FileAppender.MinimalLock"/>)
+    /// or synchronize by using a named system wide Mutex (<see 
cref="FileAppender.InterProcessLock"/>).
+    /// </para>
+    /// <para>
+    /// All locking strategies have issues and you should seriously consider 
using a different strategy that
+    /// avoids having multiple processes logging to the same file.
+    /// </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>
+#else
+       /// <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.ExclusiveLock"/> 
+       /// is to obtain an exclusive write lock on the file until this 
appender is closed.
+       /// The alternative model only holds a
+    /// write lock while the appender is writing a logging event (<see 
cref="FileAppender.MinimalLock"/>).
+       /// </para>
+    /// <para>
+    /// All locking strategies have issues and you should seriously consider 
using a different strategy that
+    /// avoids having multiple processes logging to the same file.
+    /// </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>
+#endif
+    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>
+               private sealed class LockingStream : Stream, IDisposable
+               {
+                       public sealed class LockStateException : LogException
+                       {
+                               public LockStateException(string message): 
base(message)
+                               {
+                               }
+                       }
+
+                       private Stream m_realStream=null;
+                       private LockingModelBase m_lockingModel=null;
+                       private int m_readTotal=-1;
+                       private int m_lockLevel=0;
+
+                       public LockingStream(LockingModelBase locking) : base()
+                       {
+                               if (locking==null)
+                               {
+                                       throw new ArgumentException("Locking 
model may not be null","locking");
+                               }
+                               m_lockingModel=locking;
+                       }
+
+                       #region Override Implementation of Stream
+
+                       // Methods
+                       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;
+                       }
+
+                       public override void Close() 
+                       {
+                               m_lockingModel.CloseFile();
+                       }
+
+                       public override int EndRead(IAsyncResult asyncResult) 
+                       {
+                               AssertLocked();
+                               return m_readTotal;
+                       }
+                       public override void EndWrite(IAsyncResult asyncResult) 
+                       {
+                               //No-op, it has already been handled
+                       }
+                       public override void Flush() 
+                       {
+                               AssertLocked();
+                               m_realStream.Flush();
+                       }
+                       public override int Read(byte[] buffer, int offset, int 
count) 
+                       {
+                               return m_realStream.Read(buffer,offset,count);
+                       }
+                       public override int ReadByte() 
+                       {
+                               return m_realStream.ReadByte();
+                       }
+                       public override long Seek(long offset, SeekOrigin 
origin) 
+                       {
+                               AssertLocked();
+                               return m_realStream.Seek(offset,origin);
+                       }
+                       public override void SetLength(long value) 
+                       {
+                               AssertLocked();
+                               m_realStream.SetLength(value);
+                       }
+                       void IDisposable.Dispose() 
+                       {
+                               Close();
+                       }
+                       public override void Write(byte[] buffer, int offset, 
int count) 
+                       {
+                               AssertLocked();
+                               m_realStream.Write(buffer,offset,count);
+                       }
+                       public override void WriteByte(byte value) 
+                       {
+                               AssertLocked();
+                               m_realStream.WriteByte(value);
+                       }
+
+                       // Properties
+                       public override bool CanRead 
+                       { 
+                               get { return false; } 
+                       }
+                       public override bool CanSeek 
+                       { 
+                               get 
+                               {
+                                       AssertLocked();
+                                       return m_realStream.CanSeek;
+                               } 
+                       }
+                       public override bool CanWrite 
+                       { 
+                               get 
+                               {
+                                       AssertLocked();
+                                       return m_realStream.CanWrite;
+                               } 
+                       }
+                       public override long Length 
+                       { 
+                               get 
+                               {
+                                       AssertLocked();
+                                       return m_realStream.Length;
+                               } 
+                       }
+                       public override long Position 
+                       { 
+                               get 
+                               {
+                                       AssertLocked();
+                                       return m_realStream.Position;
+                               } 
+                               set 
+                               {
+                                       AssertLocked();
+                                       m_realStream.Position=value;
+                               } 
+                       }
+
+                       #endregion Override Implementation of Stream
+
+                       #region Locking Methods
+
+                       private void AssertLocked()
+                       {
+                               if (m_realStream == null)
+                               {
+                                       throw new LockStateException("The file 
is not currently locked");
+                               }
+                       }
+
+                       public bool AcquireLock()
+                       {
+                               bool ret=false;
+                               lock(this)
+                               {
+                                       if (m_lockLevel==0)
+                                       {
+                                               // If lock is already acquired, 
nop
+                                               
m_realStream=m_lockingModel.AcquireLock();
+                                       }
+                                       if (m_realStream!=null)
+                                       {
+                                               m_lockLevel++;
+                                               ret=true;
+                                       }
+                               }
+                               return ret;
+                       }
+
+                       public void ReleaseLock()
+                       {
+                               lock(this)
+                               {
+                                       m_lockLevel--;
+                                       if (m_lockLevel==0)
+                                       {
+                                               // If already unlocked, nop
+                                               m_lockingModel.ReleaseLock();
+                                               m_realStream=null;
+                                       }
+                               }
+                       }
+
+                       #endregion Locking Methods
+               }
+
+               #endregion LockingStream Inner Class
+
+               #region Locking Models
+
+               /// <summary>
+               /// Locking model base class
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Base class for the locking models available to the <see 
cref="FileAppender"/> derived loggers.
+               /// </para>
+               /// </remarks>
+               public abstract class LockingModelBase
+               {
+                       private FileAppender m_appender=null;
+
+                       /// <summary>
+                       /// Open the output file
+                       /// </summary>
+                       /// <param name="filename">The filename to use</param>
+                       /// <param name="append">Whether to append to the file, 
or overwrite</param>
+                       /// <param name="encoding">The encoding to use</param>
+                       /// <remarks>
+                       /// <para>
+                       /// Open the file specified and prepare for logging. 
+                       /// No writes will be made until <see 
cref="AcquireLock"/> is called.
+                       /// Must be called before any calls to <see 
cref="AcquireLock"/>,
+                       /// <see cref="ReleaseLock"/> and <see 
cref="CloseFile"/>.
+                       /// </para>
+                       /// </remarks>
+                       public abstract void OpenFile(string filename, bool 
append,Encoding encoding);
+
+                       /// <summary>
+                       /// Close the file
+                       /// </summary>
+                       /// <remarks>
+                       /// <para>
+                       /// Close the file. No further writes will be made.
+                       /// </para>
+                       /// </remarks>
+                       public abstract void CloseFile();
+
+                       /// <summary>
+                       /// Acquire the lock on the file
+                       /// </summary>
+                       /// <returns>A stream that is ready to be written 
to.</returns>
+                       /// <remarks>
+                       /// <para>
+                       /// Acquire the lock on the file in preparation for 
writing to it. 
+                       /// Return a stream pointing to the file. <see 
cref="ReleaseLock"/>
+                       /// must be called to release the lock on the output 
file.
+                       /// </para>
+                       /// </remarks>
+                       public abstract Stream AcquireLock();
+
+                       /// <summary>
+                       /// Release the lock on the file
+                       /// </summary>
+                       /// <remarks>
+                       /// <para>
+                       /// Release the lock on the file. No further writes 
will be made to the 
+                       /// stream until <see cref="AcquireLock"/> is called 
again.
+                       /// </para>
+                       /// </remarks>
+                       public abstract void ReleaseLock();
+
+                       /// <summary>
+                       /// Gets or sets the <see cref="FileAppender"/> for 
this LockingModel
+                       /// </summary>
+                       /// <value>
+                       /// The <see cref="FileAppender"/> for this LockingModel
+                       /// </value>
+                       /// <remarks>
+                       /// <para>
+                       /// The file appender this locking model is attached to 
and working on
+                       /// behalf of.
+                       /// </para>
+                       /// <para>
+                       /// The file appender is used to locate the security 
context and the error handler to use.
+                       /// </para>
+                       /// <para>
+                       /// The value of this property will be set before <see 
cref="OpenFile"/> is
+                       /// called.
+                       /// </para>
+                       /// </remarks>
+                       public FileAppender CurrentAppender
+                       {
+                               get { return m_appender; }
+                               set { m_appender = value; }
+                       }
+
+            /// <summary>
+            /// Helper method that creates a FileStream under 
CurrentAppender's SecurityContext.
+            /// </summary>
+            /// <remarks>
+            /// <para>
+            /// Typically called during OpenFile or AcquireLock. 
+            /// </para>
+            /// <para>
+            /// If the directory portion of the <paramref name="filename"/> 
does not exist, it is created
+            /// via Directory.CreateDirecctory.
+            /// </para>
+            /// </remarks>
+            /// <param name="filename"></param>
+            /// <param name="append"></param>
+            /// <param name="fileShare"></param>
+            /// <returns></returns>
+            protected Stream CreateStream(string filename, bool append, 
FileShare fileShare)
+            {
+                using (CurrentAppender.SecurityContext.Impersonate(this))
+                {
+                    // Ensure that the directory structure exists
+                    string directoryFullName = Path.GetDirectoryName(filename);
+
+                    // Only create the directory if it does not exist
+                    // doing this check here resolves some permissions failures
+                    if (!Directory.Exists(directoryFullName))
+                    {
+                        Directory.CreateDirectory(directoryFullName);
+                    }
+
+                    FileMode fileOpenMode = append ? FileMode.Append : 
FileMode.Create;
+                    return new FileStream(filename, fileOpenMode, 
FileAccess.Write, fileShare);
+                }
+            }
+
+            /// <summary>
+            /// Helper method to close <paramref name="stream"/> under 
CurrentAppender's SecurityContext.
+            /// </summary>
+            /// <remarks>
+            /// Does not set <paramref name="stream"/> to null.
+            /// </remarks>
+            /// <param name="stream"></param>
+            protected void CloseStream(Stream stream)
+            {
+                using (CurrentAppender.SecurityContext.Impersonate(this))
+                {
+                    stream.Close();
+                }
+           }
+               }
+
+               /// <summary>
+               /// Hold an exclusive lock on the output file
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Open the file once for writing and hold it open until <see 
cref="CloseFile"/> is called. 
+               /// Maintains an exclusive lock on the file during this time.
+               /// </para>
+               /// </remarks>
+               public class ExclusiveLock : LockingModelBase
+               {
+                       private Stream m_stream = null;
+
+                       /// <summary>
+                       /// Open the file specified and prepare for logging.
+                       /// </summary>
+                       /// <param name="filename">The filename to use</param>
+                       /// <param name="append">Whether to append to the file, 
or overwrite</param>
+                       /// <param name="encoding">The encoding to use</param>
+                       /// <remarks>
+                       /// <para>
+                       /// Open the file specified and prepare for logging. 
+                       /// No writes will be made until <see 
cref="AcquireLock"/> is called.
+                       /// Must be called before any calls to <see 
cref="AcquireLock"/>,
+                       /// <see cref="ReleaseLock"/> and <see 
cref="CloseFile"/>.
+                       /// </para>
+                       /// </remarks>
+                       public override void OpenFile(string filename, bool 
append,Encoding encoding)
+                       {
+                               try
+                               {
+                    m_stream = CreateStream(filename, append, FileShare.Read);
+                               }
+                               catch (Exception e1)
+                               {
+                                       
CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file 
"+filename+". "+e1.Message);
+                               }
+                       }
+
+                       /// <summary>
+                       /// Close the file
+                       /// </summary>
+                       /// <remarks>
+                       /// <para>
+                       /// Close the file. No further writes will be made.
+                       /// </para>
+                       /// </remarks>
+                       public override void CloseFile()
+                       {
+                CloseStream(m_stream);
+                m_stream = null;
+                       }
+
+                       /// <summary>
+                       /// Acquire the lock on the file
+                       /// </summary>
+                       /// <returns>A stream that is ready to be written 
to.</returns>
+                       /// <remarks>
+                       /// <para>
+                       /// Does nothing. The lock is already taken
+                       /// </para>
+                       /// </remarks>
+                       public override Stream AcquireLock()
+                       {
+                               return m_stream;
+                       }
+
+                       /// <summary>
+                       /// Release the lock on the file
+                       /// </summary>
+                       /// <remarks>
+                       /// <para>
+                       /// Does nothing. The lock will be released when the 
file is closed.
+                       /// </para>
+                       /// </remarks>
+                       public override void ReleaseLock()
+                       {
+                               //NOP
+                       }
+               }
+
+               /// <summary>
+               /// Acquires the file lock for each write
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Opens the file once for each <see cref="AcquireLock"/>/<see 
cref="ReleaseLock"/> cycle, 
+               /// thus holding the lock for the minimal amount of time. This 
method of locking
+               /// is considerably slower than <see 
cref="FileAppender.ExclusiveLock"/> but allows 
+               /// other processes to move/delete the log file whilst logging 
continues.
+               /// </para>
+               /// </remarks>
+               public class MinimalLock : LockingModelBase
+               {
+                       private string m_filename;
+                       private bool m_append;
+                       private Stream m_stream=null;
+
+                       /// <summary>
+                       /// Prepares to open the file when the first message is 
logged.
+                       /// </summary>
+                       /// <param name="filename">The filename to use</param>
+                       /// <param name="append">Whether to append to the file, 
or overwrite</param>
+                       /// <param name="encoding">The encoding to use</param>
+                       /// <remarks>
+                       /// <para>
+                       /// Open the file specified and prepare for logging. 
+                       /// No writes will be made until <see 
cref="AcquireLock"/> is called.
+                       /// Must be called before any calls to <see 
cref="AcquireLock"/>,
+                       /// <see cref="ReleaseLock"/> and <see 
cref="CloseFile"/>.
+                       /// </para>
+                       /// </remarks>
+                       public override void OpenFile(string filename, bool 
append, Encoding encoding)
+                       {
+                               m_filename=filename;
+                               m_append=append;
+                       }
+
+                       /// <summary>
+                       /// Close the file
+                       /// </summary>
+                       /// <remarks>
+                       /// <para>
+                       /// Close the file. No further writes will be made.
+                       /// </para>
+                       /// </remarks>
+                       public override void CloseFile()
+                       {
+                               // NOP
+                       }
+
+                       /// <summary>
+                       /// Acquire the lock on the file
+                       /// </summary>
+                       /// <returns>A stream that is ready to be written 
to.</returns>
+                       /// <remarks>
+                       /// <para>
+                       /// Acquire the lock on the file in preparation for 
writing to it. 
+                       /// Return a stream pointing to the file. <see 
cref="ReleaseLock"/>
+                       /// must be called to release the lock on the output 
file.
+                       /// </para>
+                       /// </remarks>
+                       public override Stream AcquireLock()
+                       {
+                               if (m_stream==null)
+                               {
+                                       try
+                                       {
+                        m_stream = CreateStream(m_filename, m_append, 
FileShare.Read);
+                        m_append = true;
+                                       }
+                                       catch (Exception e1)
+                                       {
+                                               
CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file 
"+m_filename+". "+e1.Message);
+                                       }
+                               }
+                               return m_stream;
+                       }
+
+                       /// <summary>
+                       /// Release the lock on the file
+                       /// </summary>
+                       /// <remarks>
+                       /// <para>
+                       /// Release the lock on the file. No further writes 
will be made to the 
+                       /// stream until <see cref="AcquireLock"/> is called 
again.
+                       /// </para>
+                       /// </remarks>
+                       public override void ReleaseLock()
+                       {
+                CloseStream(m_stream);
+                m_stream = null;
+                       }
+               }
+
+#if !NETCF
+        /// <summary>
+        /// Provides cross-process file locking.
+        /// </summary>
+        /// <author>Ron Grabowski</author>
+        /// <author>Steve Wranovsky</author>
+        public class InterProcessLock : LockingModelBase
+        {
+            private Mutex m_mutex = null;
+            private Stream m_stream = null;
+
+            /// <summary>
+            /// Open the file specified and prepare for logging.
+            /// </summary>
+            /// <param name="filename">The filename to use</param>
+            /// <param name="append">Whether to append to the file, or 
overwrite</param>
+            /// <param name="encoding">The encoding to use</param>
+            /// <remarks>
+            /// <para>
+            /// Open the file specified and prepare for logging. 
+            /// No writes will be made until <see cref="AcquireLock"/> is 
called.
+            /// Must be called before any calls to <see cref="AcquireLock"/>,
+            /// -<see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
+            /// </para>
+            /// </remarks>
+#if NET_4_0 || MONO_4_0
+            [System.Security.SecuritySafeCritical]
+#endif
+            public override void OpenFile(string filename, bool append, 
Encoding encoding)
+            {
+                try
+                {
+                    m_stream = CreateStream(filename, append, 
FileShare.ReadWrite);
+
+                    string mutexFriendlyFilename = filename
+                            .Replace("\\", "_")
+                            .Replace(":", "_")
+                            .Replace("/", "_");
+
+                    m_mutex = new Mutex(false, mutexFriendlyFilename); 
+                }
+                catch (Exception e1)
+                {
+                    CurrentAppender.ErrorHandler.Error("Unable to acquire lock 
on file " + filename + ". " + e1.Message);
+                }
+            }
+
+            /// <summary>
+            /// Close the file
+            /// </summary>
+            /// <remarks>
+            /// <para>
+            /// Close the file. No further writes will be made.
+            /// </para>
+            /// </remarks>
+            public override void CloseFile()
+            {
+                try {
+                    CloseStream(m_stream);
+                    m_stream = null;
+                }
+                finally {
+                                       ReleaseLock();
+                    m_mutex.Close();
+                                       m_mutex = null;
+                }
+            }
+
+            /// <summary>
+            /// Acquire the lock on the file
+            /// </summary>
+            /// <returns>A stream that is ready to be written to.</returns>
+            /// <remarks>
+            /// <para>
+            /// Does nothing. The lock is already taken
+            /// </para>
+            /// </remarks>
+            public override Stream AcquireLock()
+            {
+                if (m_mutex != null)
+                               {
+                    // TODO: add timeout?
+                    m_mutex.WaitOne();
+
+                    // should always be true (and fast) for FileStream
+                    if (m_stream.CanSeek) {
+                        m_stream.Seek(0, SeekOrigin.End);
+                    }
+                               }
+                               else
+                               {
+                                       
CurrentAppender.ErrorHandler.Error("Programming error, no mutex available to 
acquire lock! From here on things will be dangerous!");
+                               }
+                return m_stream;
+            }
+
+            /// <summary>
+            /// Releases the lock and allows others to acquire a lock.
+            /// </summary>
+            public override void ReleaseLock()
+            {
+                if (m_mutex != null)
+                {
+                    m_mutex.ReleaseMutex();
+                               }
+                               else
+                               {
+                                       
CurrentAppender.ErrorHandler.Error("Programming error, no mutex available to 
release the lock!");
+                               }
+            }
+        }
+#endif
+
+               #endregion Locking Models
+
+               #region Public Instance Constructors
+
+               /// <summary>
+               /// Default constructor
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Default constructor
+               /// </para>
+               /// </remarks>
+               public FileAppender()
+               {
+               }
+
+               /// <summary>
+               /// Construct a new appender using the layout, file and append 
mode.
+               /// </summary>
+               /// <param name="layout">the layout to use with this 
appender</param>
+               /// <param name="filename">the full path to the file to write 
to</param>
+               /// <param name="append">flag to indicate if the file should be 
appended to</param>
+               /// <remarks>
+               /// <para>
+               /// Obsolete constructor.
+               /// </para>
+               /// </remarks>
+               [Obsolete("Instead use the default constructor and set the 
Layout, File & AppendToFile properties")]
+               public FileAppender(ILayout layout, string filename, bool 
append) 
+               {
+                       Layout = layout;
+                       File = filename;
+                       AppendToFile = append;
+                       ActivateOptions();
+               }
+
+               /// <summary>
+               /// Construct a new appender using the layout and file 
specified.
+               /// The file will be appended to.
+               /// </summary>
+               /// <param name="layout">the layout to use with this 
appender</param>
+               /// <param name="filename">the full path to the file to write 
to</param>
+               /// <remarks>
+               /// <para>
+               /// Obsolete constructor.
+               /// </para>
+               /// </remarks>
+               [Obsolete("Instead use the default constructor and set the 
Layout & File properties")]
+               public FileAppender(ILayout layout, string filename) : 
this(layout, filename, true)
+               {
+               }
+
+               #endregion Public Instance Constructors
+
+               #region Public Instance Properties
+
+               /// <summary>
+               /// Gets or sets the path to the file that logging will be 
written to.
+               /// </summary>
+               /// <value>
+               /// The path to the file that logging will be written to.
+               /// </value>
+               /// <remarks>
+               /// <para>
+               /// If the path is relative it is taken as relative from 
+               /// the application base directory.
+               /// </para>
+               /// </remarks>
+               virtual public string File
+               {
+                       get { return m_fileName; }
+                       set { m_fileName = value; }
+               }
+
+               /// <summary>
+               /// Gets or sets a flag that indicates whether the file should 
be
+               /// appended to or overwritten.
+               /// </summary>
+               /// <value>
+               /// Indicates whether the file should be appended to or 
overwritten.
+               /// </value>
+               /// <remarks>
+               /// <para>
+               /// If the value is set to false then the file will be 
overwritten, if 
+               /// it is set to true then the file will be appended to.
+               /// </para>
+               /// The default value is true.
+               /// </remarks>
+               public bool AppendToFile
+               {
+                       get { return m_appendToFile; }
+                       set { m_appendToFile = value; }
+               }
+
+               /// <summary>
+               /// Gets or sets <see cref="Encoding"/> used to write to the 
file.
+               /// </summary>
+               /// <value>
+               /// The <see cref="Encoding"/> used to write to the file.
+               /// </value>
+               /// <remarks>
+               /// <para>
+               /// The default encoding set is <see 
cref="System.Text.Encoding.Default"/>
+               /// which is the encoding for the system's current ANSI code 
page.
+               /// </para>
+               /// </remarks>
+               public Encoding Encoding
+               {
+                       get { return m_encoding; }
+                       set { m_encoding = value; }
+               }
+
+               /// <summary>
+               /// Gets or sets the <see cref="SecurityContext"/> used to 
write to the file.
+               /// </summary>
+               /// <value>
+               /// The <see cref="SecurityContext"/> used to write to the file.
+               /// </value>
+               /// <remarks>
+               /// <para>
+               /// Unless a <see cref="SecurityContext"/> specified here for 
this appender
+               /// the <see cref="SecurityContextProvider.DefaultProvider"/> 
is queried for the
+               /// security context to use. The default behavior is to use the 
security context
+               /// of the current thread.
+               /// </para>
+               /// </remarks>
+               public SecurityContext SecurityContext 
+               {
+                       get { return m_securityContext; }
+                       set { m_securityContext = value; }
+               }
+
+#if NETCF
+               /// <summary>
+               /// Gets or sets the <see cref="FileAppender.LockingModel"/> 
used to handle locking of the file.
+               /// </summary>
+               /// <value>
+               /// The <see cref="FileAppender.LockingModel"/> used to lock 
the file.
+               /// </value>
+               /// <remarks>
+               /// <para>
+               /// Gets or sets the <see cref="FileAppender.LockingModel"/> 
used to handle locking of the file.
+               /// </para>
+               /// <para>
+        /// There are two built in locking models, <see 
cref="FileAppender.ExclusiveLock"/> and <see cref="FileAppender.MinimalLock"/>.
+               /// The first locks the file from the start of logging to the 
end, the 
+               /// second locks only for the minimal amount of time when 
logging each message
+        /// and the last synchronizes processes using a named system wide 
Mutex.
+               /// </para>
+               /// <para>
+               /// The default locking model is the <see 
cref="FileAppender.ExclusiveLock"/>.
+               /// </para>
+               /// </remarks>
+#else
+        /// <summary>
+               /// Gets or sets the <see cref="FileAppender.LockingModel"/> 
used to handle locking of the file.
+               /// </summary>
+               /// <value>
+               /// The <see cref="FileAppender.LockingModel"/> used to lock 
the file.
+               /// </value>
+               /// <remarks>
+               /// <para>
+               /// Gets or sets the <see cref="FileAppender.LockingModel"/> 
used to handle locking of the file.
+               /// </para>
+               /// <para>
+        /// There are three built in locking models, <see 
cref="FileAppender.ExclusiveLock"/>, <see cref="FileAppender.MinimalLock"/> and 
<see cref="FileAppender.InterProcessLock"/> .
+               /// The first locks the file from the start of logging to the 
end, the 
+               /// second locks only for the minimal amount of time when 
logging each message
+        /// and the last synchronizes processes using a named system wide 
Mutex.
+               /// </para>
+               /// <para>
+               /// The default locking model is the <see 
cref="FileAppender.ExclusiveLock"/>.
+               /// </para>
+               /// </remarks>
+#endif
+               public FileAppender.LockingModelBase LockingModel
+               {
+                       get { return m_lockingModel; }
+                       set { m_lockingModel = value; }
+               }
+
+               #endregion Public Instance Properties
+
+               #region Override implementation of AppenderSkeleton
+
+               /// <summary>
+               /// Activate the options on the file appender. 
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// This is part of the <see cref="IOptionHandler"/> delayed 
object
+               /// activation scheme. The <see cref="ActivateOptions"/> method 
must 
+               /// be called on this object after the configuration properties 
have
+               /// been set. Until <see cref="ActivateOptions"/> is called this
+               /// object is in an undefined state and must not be used. 
+               /// </para>
+               /// <para>
+               /// If any of the configuration properties are modified then 
+               /// <see cref="ActivateOptions"/> must be called again.
+               /// </para>
+               /// <para>
+               /// This will cause the file to be opened.
+               /// </para>
+               /// </remarks>
+               override public void ActivateOptions() 
+               {       
+                       base.ActivateOptions();
+
+                       if (m_securityContext == null)
+                       {
+                               m_securityContext = 
SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
+                       }
+
+                       if (m_lockingModel == null)
+                       {
+                               m_lockingModel = new 
FileAppender.ExclusiveLock();
+                       }
+
+                       m_lockingModel.CurrentAppender=this;
+                       
+                       if (m_fileName != null) 
+                       {
+                               using(SecurityContext.Impersonate(this))
+                               {
+                                       m_fileName = 
ConvertToFullPath(m_fileName.Trim());
+                               }
+                               SafeOpenFile(m_fileName, m_appendToFile);
+                       } 
+                       else 
+                       {
+                               LogLog.Warn(declaringType, "FileAppender: File 
option not set for appender ["+Name+"].");
+                               LogLog.Warn(declaringType, "FileAppender: Are 
you using FileAppender instead of ConsoleAppender?");
+                       }
+               }
+
+               #endregion Override implementation of AppenderSkeleton
+
+               #region Override implementation of TextWriterAppender
+
+               /// <summary>
+               /// Closes any previously opened file and calls the parent's 
<see cref="TextWriterAppender.Reset"/>.
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Resets the filename and the file stream.
+               /// </para>
+               /// </remarks>
+               override protected void Reset() 
+               {
+                       base.Reset();
+                       m_fileName = null;
+               }
+
+               /// <summary>
+               /// Called to initialize the file writer
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Will be called for each logged message until the file is
+               /// successfully opened.
+               /// </para>
+               /// </remarks>
+               override protected void PrepareWriter()
+               {
+                       SafeOpenFile(m_fileName, m_appendToFile);
+               }
+
+               /// <summary>
+               /// This method is called by the <see 
cref="M:AppenderSkeleton.DoAppend(LoggingEvent)"/>
+               /// method. 
+               /// </summary>
+               /// <param name="loggingEvent">The event to log.</param>
+               /// <remarks>
+               /// <para>
+               /// Writes a log statement to the output stream if the output 
stream exists 
+               /// and is writable.  
+               /// </para>
+               /// <para>
+               /// The format of the output will depend on the appender's 
layout.
+               /// </para>
+               /// </remarks>
+               override protected void Append(LoggingEvent loggingEvent) 
+               {
+                       if (m_stream.AcquireLock())
+                       {
+                               try
+                               {
+                                       base.Append(loggingEvent);
+                               }
+                               finally
+                               {
+                                       m_stream.ReleaseLock();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// This method is called by the <see 
cref="M:AppenderSkeleton.DoAppend(LoggingEvent[])"/>
+               /// method. 
+               /// </summary>
+               /// <param name="loggingEvents">The array of events to 
log.</param>
+               /// <remarks>
+               /// <para>
+               /// Acquires the output file locks once before writing all the 
events to
+               /// the stream.
+               /// </para>
+               /// </remarks>
+               override protected void Append(LoggingEvent[] loggingEvents) 
+               {
+                       if (m_stream.AcquireLock())
+                       {
+                               try
+                               {
+                                       base.Append(loggingEvents);
+                               }
+                               finally
+                               {
+                                       m_stream.ReleaseLock();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Writes a footer as produced by the embedded layout's <see 
cref="ILayout.Footer"/> property.
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Writes a footer as produced by the embedded layout's <see 
cref="ILayout.Footer"/> property.
+               /// </para>
+               /// </remarks>
+               protected override void WriteFooter() 
+               {
+                       if (m_stream!=null)
+                       {
+                               //WriteFooter can be called even before a file 
is opened
+                               m_stream.AcquireLock();
+                               try
+                               {
+                                       base.WriteFooter();
+                               }
+                               finally
+                               {
+                                       m_stream.ReleaseLock();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Writes a header produced by the embedded layout's <see 
cref="ILayout.Header"/> property.
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Writes a header produced by the embedded layout's <see 
cref="ILayout.Header"/> property.
+               /// </para>
+               /// </remarks>
+               protected override void WriteHeader() 
+               {
+                       if (m_stream!=null)
+                       {
+                               if (m_stream.AcquireLock())
+                               {
+                                       try
+                                       {
+                                               base.WriteHeader();
+                                       }
+                                       finally
+                                       {
+                                               m_stream.ReleaseLock();
+                                       }
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Closes the underlying <see cref="TextWriter"/>.
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Closes the underlying <see cref="TextWriter"/>.
+               /// </para>
+               /// </remarks>
+               protected override void CloseWriter() 
+               {
+                       if (m_stream!=null)
+                       {
+                               m_stream.AcquireLock();
+                               try
+                               {
+                                       base.CloseWriter();
+                               }
+                               finally
+                               {
+                                       m_stream.ReleaseLock();
+                               }
+                       }
+               }
+
+               #endregion Override implementation of TextWriterAppender
+
+               #region Public Instance Methods
+
+               /// <summary>
+               /// Closes the previously opened file.
+               /// </summary>
+               /// <remarks>
+               /// <para>
+               /// Writes the <see cref="ILayout.Footer"/> to the file and then
+               /// closes the file.
+               /// </para>
+               /// </remarks>
+               protected void CloseFile() 
+               {
+                       WriteFooterAndCloseWriter();
+               }
+
+               #endregion Public Instance Methods
+
+               #region Protected Instance Methods
+
+               /// <summary>
+               /// Sets and <i>opens</i> the file where the log output will 
go. The specified file must be writable.
+               /// </summary>
+               /// <param name="fileName">The path to the log file. Must be a 
fully qualified path.</param>
+               /// <param name="append">If true will append to fileName. 
Otherwise will truncate fileName</param>
+               /// <remarks>
+               /// <para>
+               /// Calls <see cref="OpenFile"/> but guarantees not to throw an 
exception.
+               /// Errors are passed to the <see 
cref="TextWriterAppender.ErrorHandler"/>.
+               /// </para>
+               /// </remarks>
+               virtual protected void SafeOpenFile(string fileName, bool 
append)
+               {
+                       try 
+                       {
+                               OpenFile(fileName, append);
+                       }
+                       catch(Exception e) 
+                       {
+                               
ErrorHandler.Error("OpenFile("+fileName+","+append+") call failed.", e, 
ErrorCode.FileOpenFailure);
+                       }
+               }
+
+               /// <summary>
+               /// Sets and <i>opens</i> the file where the log output will 
go. The specified file must be writable.
+               /// </summary>
+               /// <param name="fileName">The path to the log file. Must be a 
fully qualified path.</param>
+               /// <param name="append">If true will append to fileName. 
Otherwise will truncate fileName</param>
+               /// <remarks>
+               /// <para>
+               /// If there was already an opened file, then the previous file
+               /// is closed first.
+               /// </para>
+               /// <para>
+               /// This method will ensure that the directory structure
+               /// for the <paramref name="fileName"/> specified exists.
+               /// </para>
+               /// </remarks>
+               virtual protected void OpenFile(string fileName, bool append)
+               {
+                       if (LogLog.IsErrorEnabled)
+                       {
+                               // Internal check that the fileName passed in 
is a rooted path
+                               bool isPathRooted = false;
+                               using(SecurityContext.Impersonate(this))
+                               {
+                                       isPathRooted = 
Path.IsPathRooted(fileName);
+                               }
+                               if (!isPathRooted)
+                               {
+                                       LogLog.Error(declaringType, "INTERNAL 
ERROR. OpenFile("+fileName+"): File name is not fully qualified.");
+                               }
+                       }
+
+                       lock(this)
+                       {
+                               Reset();
+
+                               LogLog.Debug(declaringType, "Opening file for 
writing ["+fileName+"] append ["+append+"]");
+
+                               // Save these for later, allowing retries if 
file open fails
+                               m_fileName = fileName;
+                               m_appendToFile = append;
+
+                               LockingModel.CurrentAppender=this;
+                               
LockingModel.OpenFile(fileName,append,m_encoding);
+                               m_stream=new LockingStream(LockingModel);
+
+                               if (m_stream != null)
+                               {
+                                       m_stream.AcquireLock();
+                                       try
+                                       {
+                                               SetQWForFiles(new 
StreamWriter(m_stream, m_encoding));
+                                       }
+                                       finally
+                                       {
+                                               m_stream.ReleaseLock();
+                                       }
+                               }
+
+                               WriteHeader();
+                       }
+               }
+
+               /// <summary>
+               /// Sets the quiet writer used for file output
+               /// </summary>
+               /// <param name="fileStream">the file stream that has been 
opened for writing</param>
+               /// <remarks>
+               /// <para>
+               /// This implementation of <see 
cref="M:SetQWForFiles(Stream)"/> creates a <see cref="StreamWriter"/>
+               /// over the <paramref name="fileStream"/> and passes it to the 
+               /// <see cref="M:SetQWForFiles(TextWriter)"/> method.
+               /// </para>
+               /// <para>
+               /// This method can be overridden by sub classes that want to 
wrap the
+               /// <see cref="Stream"/> in some way, for example to encrypt 
the output
+               /// data using a 
<c>System.Security.Cryptography.CryptoStream</c>.
+               /// </para>
+               /// </remarks>
+               virtual protected void SetQWForFiles(Stream fileStream) 
+               {
+                       SetQWForFiles(new StreamWriter(fileStream, m_encoding));
+               }
+
+               /// <summary>
+               /// Sets the quiet writer being used.
+               /// </summary>
+               /// <param name="writer">the writer over the file stream that 
has been opened for writing</param>
+               /// <remarks>
+               /// <para>
+               /// This method can be overridden by sub classes that want to
+               /// wrap the <see cref="TextWriter"/> in some way.
+               /// </para>
+               /// </remarks>
+               virtual protected void SetQWForFiles(TextWriter writer) 
+               {
+                       QuietWriter = new QuietTextWriter(writer, ErrorHandler);
+               }
+
+               #endregion Protected Instance Methods
+
+               #region Protected Static Methods
+
+               /// <summary>
+               /// Convert a path into a fully qualified path.
+               /// </summary>
+               /// <param name="path">The path to convert.</param>
+               /// <returns>The fully qualified path.</returns>
+               /// <remarks>
+               /// <para>
+               /// Converts the path specified to a fully
+               /// qualified path. If the path is relative it is
+               /// taken as relative from the application base 
+               /// directory.
+               /// </para>
+               /// </remarks>
+               protected static string ConvertToFullPath(string path)
+               {
+                       return SystemInfo.ConvertToFullPath(path);
+               }
+
+               #endregion Protected Static Methods
+
+               #region Private Instance Fields
+
+               /// <summary>
+               /// Flag to indicate if we should append to the file
+               /// or overwrite the file. The default is to append.
+               /// </summary>
+               private bool m_appendToFile = true;
+
+               /// <summary>
+               /// The name of the log file.
+               /// </summary>
+               private string m_fileName = null;
+
+               /// <summary>
+               /// The encoding to use for the file stream.
+               /// </summary>
+               private Encoding m_encoding = Encoding.Default;
+
+               /// <summary>
+               /// The security context to use for privileged calls
+               /// </summary>
+               private SecurityContext m_securityContext;
+
+               /// <summary>
+               /// The stream to log to. Has added locking semantics
+               /// </summary>
+               private FileAppender.LockingStream m_stream = null;
+
+               /// <summary>
+               /// The locking model to use
+               /// </summary>
+               private FileAppender.LockingModelBase m_lockingModel = new 
FileAppender.ExclusiveLock();
+
+               #endregion Private Instance Fields
+
+           #region Private Static Fields
+
+           /// <summary>
+           /// The fully qualified type of the FileAppender class.
+           /// </summary>
+           /// <remarks>
+           /// Used by the internal logger to record the Type of the
+           /// log message.
+           /// </remarks>
+           private readonly static Type declaringType = typeof(FileAppender);
+
+           #endregion Private Static Fields
+       }
+}

Modified: logging/log4net/trunk/tests/src/Appender/RollingFileAppenderTest.cs
URL: 
http://svn.apache.org/viewvc/logging/log4net/trunk/tests/src/Appender/RollingFileAppenderTest.cs?rev=1711829&r1=1711828&r2=1711829&view=diff
==============================================================================
--- logging/log4net/trunk/tests/src/Appender/RollingFileAppenderTest.cs 
(original)
+++ logging/log4net/trunk/tests/src/Appender/RollingFileAppenderTest.cs Sun Nov 
 1 16:29:57 2015
@@ -1397,6 +1397,20 @@ namespace log4net.Tests.Appender
                /// <returns>A configured ILogger</returns>
                private static ILogger CreateLogger(string filename, 
FileAppender.LockingModelBase lockModel, IErrorHandler handler)
                {
+                       return CreateLogger(filename, lockModel, handler, 
100000, 0);
+               }
+
+               /// <summary>
+               /// Creates a logger hierarchy, configures a rolling file 
appender and returns an ILogger
+               /// </summary>
+               /// <param name="filename">The filename to log to</param>
+               /// <param name="lockModel">The locking model to use.</param>
+               /// <param name="handler">The error handler to use.</param>
+               /// <param name="maxFileSize">Maximum file size for roll</param>
+               /// <param name="maxSizeRollBackups">Maximum number of roll 
backups</param>
+               /// <returns>A configured ILogger</returns>
+               private static ILogger CreateLogger(string filename, 
FileAppender.LockingModelBase lockModel, IErrorHandler handler, int 
maxFileSize, int maxSizeRollBackups)
+               {
                        Repository.Hierarchy.Hierarchy h = 
(Repository.Hierarchy.Hierarchy)LogManager.CreateRepository("TestRepository");
 
                        RollingFileAppender appender = new 
RollingFileAppender();
@@ -1404,9 +1418,10 @@ namespace log4net.Tests.Appender
                        appender.AppendToFile = false;
                        appender.CountDirection = 0;
                        appender.RollingStyle = 
RollingFileAppender.RollingMode.Size;
-                       appender.MaxFileSize = 100000;
+                       appender.MaxFileSize = maxFileSize;
                        appender.Encoding = Encoding.ASCII;
                        appender.ErrorHandler = handler;
+                       appender.MaxSizeRollBackups = maxSizeRollBackups;
                        if (lockModel != null)
                        {
                                appender.LockingModel = lockModel;
@@ -1686,6 +1701,28 @@ namespace log4net.Tests.Appender
             AssertFileEquals(filename, "This is a message" + 
Environment.NewLine + "Test" + Environment.NewLine + "This is a message 2" + 
Environment.NewLine);
             Assert.AreEqual("", sh.Message, "Unexpected error message");
         }
+
+               /// <summary>
+               /// Verifies that rolling file works
+               /// </summary>
+               [Test]
+               public void TestInterProcessLockRoll()
+               {
+                       String filename = "test.log";
+                       bool locked;
+
+                       SilentErrorHandler sh = new SilentErrorHandler();
+                       ILogger log = CreateLogger(filename, new 
FileAppender.InterProcessLock(), sh, 1, 2);
+
+                       Assert.DoesNotThrow(delegate { log.Log(GetType(), 
Level.Info, "A", null); });
+                       Assert.DoesNotThrow(delegate { log.Log(GetType(), 
Level.Info, "A", null); });
+                       
+                       DestroyLogger();
+
+                       AssertFileEquals(filename, "A" + Environment.NewLine);
+                       AssertFileEquals(filename + ".1", "A" + 
Environment.NewLine);
+                       Assert.IsEmpty(sh.Message);
+               }
 #endif
 
         /// <summary>


Reply via email to