Index: FileAppender.cs
===================================================================
--- FileAppender.cs (revision 718051)
+++ FileAppender.cs (working copy)
@@ -20,7 +20,7 @@
using System;
using System.IO;
using System.Text;
-
+using System.Threading;
using log4net.Util;
using log4net.Layout;
using log4net.Core;
@@ -162,7 +162,7 @@
}
void IDisposable.Dispose()
{
- this.Close();
+ Close();
}
public override void Write(byte[] buffer, int offset, int count)
{
@@ -356,6 +356,56 @@
get { return m_appender; }
set { m_appender = value; }
}
+
+ ///
+ /// Helper method that creates a FileStream under CurrentAppender's SecurityContext.
+ ///
+ ///
+ ///
+ /// Typically called during OpenFile or AcquireLock.
+ ///
+ ///
+ /// If the directory portion of the does not exist, it is created
+ /// via Directory.CreateDirecctory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ 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.Read);
+ }
+ }
+
+ ///
+ /// Helper method to close under CurrentAppender's SecurityContext.
+ ///
+ ///
+ /// Does not set to null.
+ ///
+ ///
+ protected void CloseStream(Stream stream)
+ {
+ using (CurrentAppender.SecurityContext.Impersonate(this))
+ {
+ stream.Close();
+ }
+ }
}
///
@@ -389,21 +439,7 @@
{
try
{
- 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;
- m_stream = new FileStream(filename, fileOpenMode, FileAccess.Write, FileShare.Read);
- }
+ m_stream = CreateStream(filename, append, FileShare.Read);
}
catch (Exception e1)
{
@@ -421,10 +457,8 @@
///
public override void CloseFile()
{
- using(CurrentAppender.SecurityContext.Impersonate(this))
- {
- m_stream.Close();
- }
+ CloseStream(m_stream);
+ m_stream = null;
}
///
@@ -522,22 +556,7 @@
{
try
{
- using(CurrentAppender.SecurityContext.Impersonate(this))
- {
- // Ensure that the directory structure exists
- string directoryFullName = Path.GetDirectoryName(m_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 = m_append ? FileMode.Append : FileMode.Create;
- m_stream = new FileStream(m_filename, fileOpenMode, FileAccess.Write, FileShare.Read);
- m_append=true;
- }
+ m_stream = CreateStream(m_filename, m_append, FileShare.Read);
}
catch (Exception e1)
{
@@ -558,14 +577,108 @@
///
public override void ReleaseLock()
{
- using(CurrentAppender.SecurityContext.Impersonate(this))
- {
- m_stream.Close();
- m_stream=null;
- }
+ CloseStream(m_stream);
+ m_stream = null;
}
}
+ ///
+ /// Provides cross-process file locking.
+ ///
+ /// Ron Grabowski
+ /// Steve Wranovsky
+ public class ProcessLock : LockingModelBase
+ {
+ private Mutex m_mutex = null;
+ private bool m_mutexClosed = false;
+ private Stream m_stream = null;
+
+ ///
+ /// Open the file specified and prepare for logging.
+ ///
+ /// The filename to use
+ /// Whether to append to the file, or overwrite
+ /// The encoding to use
+ ///
+ ///
+ /// Open the file specified and prepare for logging.
+ /// No writes will be made until is called.
+ /// Must be called before any calls to ,
+ /// - and .
+ ///
+ ///
+ 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);
+ }
+ catch (Exception e1)
+ {
+ CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + filename + ". " + e1.Message);
+ }
+ }
+
+ ///
+ /// Close the file
+ ///
+ ///
+ ///
+ /// Close the file. No further writes will be made.
+ ///
+ ///
+ public override void CloseFile()
+ {
+ CloseStream(m_stream);
+ m_stream = null;
+
+ m_mutex.ReleaseMutex();
+ m_mutex.Close();
+ m_mutexClosed = true;
+ }
+
+ ///
+ /// Acquire the lock on the file
+ ///
+ /// A stream that is ready to be written to.
+ ///
+ ///
+ /// Does nothing. The lock is already taken
+ ///
+ ///
+ public override Stream AcquireLock()
+ {
+ // 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;
+ }
+
+ ///
+ ///
+ ///
+ public override void ReleaseLock()
+ {
+ if (m_mutexClosed == false)
+ {
+ m_mutex.ReleaseMutex();
+ }
+ }
+ }
+
#endregion Locking Models
#region Public Instance Constructors