LogStream.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / IO / LogStream.cs / 1305376 / LogStream.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  LogStream 
**
===========================================================*/ 
using System;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System.Security; 
using System.Security.Permissions;
using System.Threading; 
using System.Runtime.InteropServices; 
using System.Runtime.Remoting.Messaging;
using System.Runtime.CompilerServices; 
using System.Globalization;
using System.Runtime.Versioning;

using System.Diagnostics; 
using System.Diagnostics.Contracts;
 
namespace System.IO { 

// This stream has very limited support to enable EventSchemaTraceListener 
// Eventually we might want to add more functionality and expose this type
internal class LogStream : BufferedStream2
{
    internal const long DefaultFileSize = 10*1000*1024; 
    internal const int DefaultNumberOfFiles = 2;
    internal const LogRetentionOption DefaultRetention = LogRetentionOption.SingleFileUnboundedSize; 
 
    // Retention policy
    private const int _retentionRetryThreshold = 2; 
    private LogRetentionOption _retention;
    private long _maxFileSize = DefaultFileSize;
    private int _maxNumberOfFiles = DefaultNumberOfFiles;
    private int _currentFileNum = 1; 
    bool _disableLogging;
    int _retentionRetryCount; 
 
    private bool _canRead;
    private bool _canWrite; 
    private bool _canSeek;
    private SafeFileHandle _handle;

    private String _fileName;       // Fully qualified file name. 
    string _fileNameWithoutExt;
    string _fileExt; 
 
    // Save input for retention
    string _pathSav; 
    int _fAccessSav;
    FileShare _shareSav;
    UnsafeNativeMethods.SECURITY_ATTRIBUTES _secAttrsSav;
    FileIOPermissionAccess _secAccessSav; 
    FileMode _modeSav;
    int _flagsAndAttributesSav; 
    bool _seekToEndSav; 

    private readonly object m_lockObject = new Object(); 

    //Limited to immediate internal need from EventSchemaTraceListener
    //Not param validation done!!
    [ResourceExposure(ResourceScope.Machine)] 
    [ResourceConsumption(ResourceScope.Machine)]
    //  
    //  
    // 
    //  
    [System.Security.SecurityCritical]
    internal LogStream(String path, int bufferSize, LogRetentionOption retention, long maxFileSize, int maxNumOfFiles)
    {
        Debug.Assert(!String.IsNullOrEmpty(path)); 

        // Get absolute path - Security needs this to prevent something 
        // like trying to create a file in c:\tmp with the name 
        // "..\WinNT\System32\ntoskrnl.exe".  Store it for user convenience.
        //String filePath = Path.GetFullPathInternal(path); 
        String filePath = Path.GetFullPath(path);
        _fileName = filePath;

        // Prevent access to your disk drives as raw block devices. 
        if (filePath.StartsWith("\\\\.\\", StringComparison.Ordinal))
            throw new NotSupportedException(SR.GetString(SR.NotSupported_IONonFileDevices)); 
 
        UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(FileShare.Read);
 
        // For mitigating local elevation of privilege attack through named pipes
        // make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
        // named pipe server can't impersonate a high privileged client security context
        int flagsAndAttributes = (int)FileOptions.None | (UnsafeNativeMethods.SECURITY_SQOS_PRESENT | UnsafeNativeMethods.SECURITY_ANONYMOUS); 

        // Only write is enabled 
        //_canRead = false; 
        //_canSeek = false;
        _canWrite = true; 

        _pathSav = filePath;
        _fAccessSav = UnsafeNativeMethods.GENERIC_WRITE;
        _shareSav = FileShare.Read; 
        _secAttrsSav = secAttrs;
        _secAccessSav = FileIOPermissionAccess.Write; 
        _modeSav = (retention != LogRetentionOption.SingleFileUnboundedSize)? FileMode.Create : FileMode.OpenOrCreate; 
        _flagsAndAttributesSav = flagsAndAttributes;
        _seekToEndSav = (retention != LogRetentionOption.SingleFileUnboundedSize)? false : true; 

        this.bufferSize = bufferSize;
        _retention = retention;
        _maxFileSize = maxFileSize; 
        _maxNumberOfFiles = maxNumOfFiles;
 
        _Init(filePath, _fAccessSav, _shareSav, _secAttrsSav, _secAccessSav, _modeSav, _flagsAndAttributesSav, _seekToEndSav); 
    }
 
    // 
    // 
    // 
    //  
    // 
    //  
    //  
    // 
    //  
    [System.Security.SecurityCritical]
    internal void _Init(String path, int fAccess, FileShare share, UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs, FileIOPermissionAccess secAccess,
                        FileMode mode, int flagsAndAttributes, bool seekToEnd)
    { 
        String filePath = Path.GetFullPath(path);
        _fileName = filePath; 
 
        new FileIOPermission(secAccess, new String[] { filePath }).Demand();
 
        // Don't pop up a dialog for reading from an emtpy floppy drive
        int oldMode = UnsafeNativeMethods.SetErrorMode(UnsafeNativeMethods.SEM_FAILCRITICALERRORS);
        try {
            _handle = UnsafeNativeMethods.SafeCreateFile(filePath, fAccess, share, secAttrs, mode, flagsAndAttributes, UnsafeNativeMethods.NULL); 
            int errorCode = Marshal.GetLastWin32Error();
 
            if (_handle.IsInvalid) { 
                // Return a meaningful exception, using the RELATIVE path to
                // the file to avoid returning extra information to the caller 
                // unless they have path discovery permission, in which case
                // the full path is fine & useful.

                // We need to give an exception, and preferably it would include 
                // the fully qualified path name.  Do security check here.  If
                // we fail, give back the msgPath, which should not reveal much. 
                // While this logic is largely duplicated in 
                // __Error.WinIOError, we need this for
                // IsolatedStorageLogFileStream. 
                bool canGiveFullPath = false;

                try {
                    new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }).Demand(); 
                    canGiveFullPath = true;
                } 
                catch(SecurityException) {} 

                if (canGiveFullPath) 
                    __Error.WinIOError(errorCode, _fileName);
                else
                    __Error.WinIOError(errorCode, Path.GetFileName(_fileName));
            } 
        }
        finally { 
            UnsafeNativeMethods.SetErrorMode(oldMode); 
        }
        Debug.Assert(UnsafeNativeMethods.GetFileType(_handle) == UnsafeNativeMethods.FILE_TYPE_DISK, "did someone accidentally removed the device type check from SafeCreateFile P/Invoke wrapper?"); 

        pos = 0;

        // For Append mode... 
        if (seekToEnd) {
            SeekCore(0, SeekOrigin.End); 
        } 
    }
 
    public override bool CanRead {
        [Pure]
        get { return _canRead; }
    } 

    public override bool CanWrite { 
        [Pure] 
        get { return _canWrite; }
    } 

    public override bool CanSeek {
        [Pure]
        get { return _canSeek; } 
    }
 
    public override long Length { 
        get {
            throw new NotSupportedException(); 
        }
    }

    public override long Position { 
        get {
            throw new NotSupportedException(); 
        } 
        set {
            throw new NotSupportedException(); 
        }
    }

    public override void SetLength(long value) 
    {
        throw new NotSupportedException(); 
    } 

    public override long Seek(long offset, SeekOrigin origin) 
    {
        throw new NotSupportedException();
    }
 
    public override int Read(byte[] array, int offset, int count)
    { 
        throw new NotSupportedException(); 
    }
 
    // 
    // 
    // 
    //  
    // 
    [System.Security.SecurityCritical] 
    protected override unsafe void WriteCore(byte[] buffer, int offset, int count, bool blockForWrite, out long streamPos) { 
        Debug.Assert(CanWrite, "CanWrite");
        Debug.Assert(buffer != null, "buffer != null"); 
        Debug.Assert(offset >= 0, "offset is negative");
        Debug.Assert(count >= 0, "count is negative");

        int hr = 0; 
        int r = WriteFileNative(buffer, offset, count, null, out hr);
        if (r == -1) { 
            // For pipes, ERROR_NO_DATA is not an error, but the pipe is closing. 
            if (hr == UnsafeNativeMethods.ERROR_NO_DATA) {
                r = 0; 
            }
            else {
                // ERROR_INVALID_PARAMETER may be returned for writes
                // where the position is too large (ie, writing at Int64.MaxValue 
                // on Win9x) OR for synchronous writes to a handle opened
                // asynchronously. 
                if (hr == UnsafeNativeMethods.ERROR_INVALID_PARAMETER) 
                    throw new IOException(SR.GetString(SR.IO_FileTooLongOrHandleNotSync));
                __Error.WinIOError(hr, String.Empty); 
            }
        }
        Debug.Assert(r >= 0, "WriteCore is likely broken.");
        // update cached position 
        streamPos = AddUnderlyingStreamPosition((long)r);
        EnforceRetentionPolicy(_handle, streamPos); 
        streamPos = pos; 
        return;
    } 

    // 
    // 
    //  
    // 
    //  
    //  
    // 
    //  
    [System.Security.SecurityCritical]
    unsafe private int WriteFileNative(byte[] bytes, int offset, int count, NativeOverlapped* overlapped, out int hr) {
        if (_handle.IsClosed) __Error.FileNotOpen();
 
        if (_disableLogging) {
            hr = 0; 
            return 0; 
        }
 
        Debug.Assert(offset >= 0, "offset >= 0");
        Debug.Assert(count >= 0, "count >= 0");
        Debug.Assert(bytes != null, "bytes != null");
 
        // Don't corrupt memory when multiple threads are erroneously writing
        // to this stream simultaneously.  (the OS is reading from 
        // the array we pass to WriteFile, but if we read beyond the end and 
        // that memory isn't allocated, we could get an AV.)
        if (bytes.Length - offset < count) 
            throw new IndexOutOfRangeException(SR.GetString(SR.IndexOutOfRange_IORaceCondition));

        // You can't use the fixed statement on an array of length 0.
        if (bytes.Length==0) { 
            hr = 0;
            return 0; 
        } 

        int numBytesWritten = 0; 
        int r = 0;

        fixed(byte* p = bytes) {
            r = UnsafeNativeMethods.WriteFile(_handle, p + offset, count, out numBytesWritten, overlapped); 
        }
 
        if (r == 0) { 
            // We should never silently ---- an error here without some
            // extra work.  We must make sure that BeginWriteCore won't return an 
            // IAsyncResult that will cause EndWrite to block, since the OS won't
            // call AsyncFSCallback for us.
            hr = Marshal.GetLastWin32Error();
 
            // For invalid handles, detect the error and mark our handle
            // as closed to give slightly better error messages.  Also 
            // help ensure we avoid handle recycling bugs. 
            if (hr == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
                _handle.SetHandleAsInvalid(); 

            return -1;
        }
        else 
            hr = 0;
        return numBytesWritten; 
    } 

    // This doesn't do argument checking.  Necessary for SetLength, which must 
    // set the file pointer beyond the end of the file. This will update the
    // internal position
    // 
    //  
    // 
    //  
    //  
    // 
    [System.Security.SecurityCritical] 
    private long SeekCore(long offset, SeekOrigin origin)
    {
        Debug.Assert(!_handle.IsClosed, "!_handle.IsClosed");
        Debug.Assert(origin>=SeekOrigin.Begin && origin<=SeekOrigin.End, "origin>=SeekOrigin.Begin && origin<=SeekOrigin.End"); 
        int hr = 0;
        long ret = 0; 
 
        ret = UnsafeNativeMethods.SetFilePointer(_handle, offset, origin, out hr);
        if (ret == -1) { 
            // For invalid handles, detect the error and mark our handle
            // as closed to give slightly better error messages.  Also
            // help ensure we avoid handle recycling bugs.
            if (hr == UnsafeNativeMethods.ERROR_INVALID_HANDLE) 
                _handle.SetHandleAsInvalid();
            __Error.WinIOError(hr, String.Empty); 
        } 

        UnderlyingStreamPosition = ret; 
        return ret;
    }

    //  
    // 
    //  
    //  
    [System.Security.SecurityCritical]
    protected override void Dispose(bool disposing) 
    {
        // Nothing will be done differently based on whether we are
        // disposing vs. finalizing.  This is taking advantage of the
        // weak ordering between normal finalizable objects & critical 
        // finalizable objects, which I included in the SafeHandle
        // design for LogStream, which would often "just work" when 
        // finalized. 
        try {
            if (_handle == null || _handle.IsClosed) { 
                // Make sure BufferedStream doesn't try to flush data on a closed handle
                DiscardBuffer();
            }
        } 
        finally {
            try { 
                // Cleanup base streams 
                base.Dispose(disposing);
            } 
            finally {
                if (_handle != null && !_handle.IsClosed)
                    _handle.Dispose();
 
                _handle = null;
                _canRead = false; 
                _canWrite = false; 
                _canSeek = false;
            } 
        }
    }

    //  
    // 
    //  
    [System.Security.SecurityCritical] 
    ~LogStream()
    { 
        if (_handle != null) {
            Dispose(false);
        }
    } 

    //  
    //  
    // 
    //  
    // 
    [System.Security.SecurityCritical]
    private void EnforceRetentionPolicy(SafeFileHandle handle, long lastPos)
    { 
        switch (_retention) {
        case LogRetentionOption.LimitedSequentialFiles: 
        case LogRetentionOption.UnlimitedSequentialFiles: 
        case LogRetentionOption.LimitedCircularFiles:
            if ((lastPos >= _maxFileSize) && (handle == _handle)){ 
                lock (m_lockObject) {
                    if ((handle != _handle) || (lastPos < _maxFileSize))
                        return;
 
                    _currentFileNum++;
                    if ((_retention == LogRetentionOption.LimitedCircularFiles) && (_currentFileNum > _maxNumberOfFiles)) { 
                        _currentFileNum = 1; 
                    }
                    else if ((_retention == LogRetentionOption.LimitedSequentialFiles) && (_currentFileNum > _maxNumberOfFiles)) { 
                        _DisableLogging();
                        return;
                    }
 
                    if (_fileNameWithoutExt == null) {
                        _fileNameWithoutExt = Path.Combine(Path.GetDirectoryName(_pathSav), Path.GetFileNameWithoutExtension(_pathSav)); 
                        _fileExt = Path.GetExtension(_pathSav); 
                    }
 
                    string path = (_currentFileNum == 1)?_pathSav: _fileNameWithoutExt + _currentFileNum.ToString(CultureInfo.InvariantCulture) + _fileExt;
                    try {
                        _Init(path, _fAccessSav, _shareSav, _secAttrsSav, _secAccessSav, _modeSav, _flagsAndAttributesSav, _seekToEndSav);
 
                        // Dispose the old handle and release the file write lock
                        // No need to flush the buffer as we just came off a write 
                        if (handle != null && !handle.IsClosed) { 
                            handle.Dispose();
                        } 
                    }
                    catch (IOException ) {
                        // Should we do this only for ERROR_SHARING_VIOLATION?
                        //if (UnsafeNativeMethods.MakeErrorCodeFromHR(Marshal.GetHRForException(ioexc)) != InternalResources.ERROR_SHARING_VIOLATION) break; 

                        // Possible sharing violation - ----? Let the next iteration try again 
                        // For now revert the handle to the original one 
                        _handle = handle;
 
                        _retentionRetryCount++;
                        if (_retentionRetryCount >= _retentionRetryThreshold) {
                            _DisableLogging();
                        } 
#if DEBUG
                        throw; 
#endif 
                    }
                    catch (UnauthorizedAccessException ) { 
                        // Indicative of ACL issues
                        _DisableLogging();
#if DEBUG
                        throw; 
#endif
                    } 
                    catch (Exception ) { 
                        _DisableLogging();
#if DEBUG 
                        throw;
#endif
                    }
                } 
            }
            break; 
 
        case LogRetentionOption.SingleFileBoundedSize:
            if (lastPos >= _maxFileSize) 
                _DisableLogging();
            break;

        case LogRetentionOption.SingleFileUnboundedSize: 
            break;
        } 
    } 

    // When we enable this class widely, we need to raise an 
    // event when we disable logging due to rention policy or
    // error such as ACL that is preventing retention
    [MethodImplAttribute(MethodImplOptions.Synchronized)]
    private void _DisableLogging() 
    {
        // Discard write buffer? 
        _disableLogging = true; 
    }
 
    // 
    // 
    // 
    [System.Security.SecurityCritical] 
    private static UnsafeNativeMethods.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share)
    { 
        UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = null; 
        if ((share & FileShare.Inheritable) != 0) {
            secAttrs = new UnsafeNativeMethods.SECURITY_ATTRIBUTES(); 
            secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);

            secAttrs.bInheritHandle = 1;
        } 
        return secAttrs;
    } 
} 
}
 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  LogStream 
**
===========================================================*/ 
using System;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System.Security; 
using System.Security.Permissions;
using System.Threading; 
using System.Runtime.InteropServices; 
using System.Runtime.Remoting.Messaging;
using System.Runtime.CompilerServices; 
using System.Globalization;
using System.Runtime.Versioning;

using System.Diagnostics; 
using System.Diagnostics.Contracts;
 
namespace System.IO { 

// This stream has very limited support to enable EventSchemaTraceListener 
// Eventually we might want to add more functionality and expose this type
internal class LogStream : BufferedStream2
{
    internal const long DefaultFileSize = 10*1000*1024; 
    internal const int DefaultNumberOfFiles = 2;
    internal const LogRetentionOption DefaultRetention = LogRetentionOption.SingleFileUnboundedSize; 
 
    // Retention policy
    private const int _retentionRetryThreshold = 2; 
    private LogRetentionOption _retention;
    private long _maxFileSize = DefaultFileSize;
    private int _maxNumberOfFiles = DefaultNumberOfFiles;
    private int _currentFileNum = 1; 
    bool _disableLogging;
    int _retentionRetryCount; 
 
    private bool _canRead;
    private bool _canWrite; 
    private bool _canSeek;
    private SafeFileHandle _handle;

    private String _fileName;       // Fully qualified file name. 
    string _fileNameWithoutExt;
    string _fileExt; 
 
    // Save input for retention
    string _pathSav; 
    int _fAccessSav;
    FileShare _shareSav;
    UnsafeNativeMethods.SECURITY_ATTRIBUTES _secAttrsSav;
    FileIOPermissionAccess _secAccessSav; 
    FileMode _modeSav;
    int _flagsAndAttributesSav; 
    bool _seekToEndSav; 

    private readonly object m_lockObject = new Object(); 

    //Limited to immediate internal need from EventSchemaTraceListener
    //Not param validation done!!
    [ResourceExposure(ResourceScope.Machine)] 
    [ResourceConsumption(ResourceScope.Machine)]
    //  
    //  
    // 
    //  
    [System.Security.SecurityCritical]
    internal LogStream(String path, int bufferSize, LogRetentionOption retention, long maxFileSize, int maxNumOfFiles)
    {
        Debug.Assert(!String.IsNullOrEmpty(path)); 

        // Get absolute path - Security needs this to prevent something 
        // like trying to create a file in c:\tmp with the name 
        // "..\WinNT\System32\ntoskrnl.exe".  Store it for user convenience.
        //String filePath = Path.GetFullPathInternal(path); 
        String filePath = Path.GetFullPath(path);
        _fileName = filePath;

        // Prevent access to your disk drives as raw block devices. 
        if (filePath.StartsWith("\\\\.\\", StringComparison.Ordinal))
            throw new NotSupportedException(SR.GetString(SR.NotSupported_IONonFileDevices)); 
 
        UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(FileShare.Read);
 
        // For mitigating local elevation of privilege attack through named pipes
        // make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
        // named pipe server can't impersonate a high privileged client security context
        int flagsAndAttributes = (int)FileOptions.None | (UnsafeNativeMethods.SECURITY_SQOS_PRESENT | UnsafeNativeMethods.SECURITY_ANONYMOUS); 

        // Only write is enabled 
        //_canRead = false; 
        //_canSeek = false;
        _canWrite = true; 

        _pathSav = filePath;
        _fAccessSav = UnsafeNativeMethods.GENERIC_WRITE;
        _shareSav = FileShare.Read; 
        _secAttrsSav = secAttrs;
        _secAccessSav = FileIOPermissionAccess.Write; 
        _modeSav = (retention != LogRetentionOption.SingleFileUnboundedSize)? FileMode.Create : FileMode.OpenOrCreate; 
        _flagsAndAttributesSav = flagsAndAttributes;
        _seekToEndSav = (retention != LogRetentionOption.SingleFileUnboundedSize)? false : true; 

        this.bufferSize = bufferSize;
        _retention = retention;
        _maxFileSize = maxFileSize; 
        _maxNumberOfFiles = maxNumOfFiles;
 
        _Init(filePath, _fAccessSav, _shareSav, _secAttrsSav, _secAccessSav, _modeSav, _flagsAndAttributesSav, _seekToEndSav); 
    }
 
    // 
    // 
    // 
    //  
    // 
    //  
    //  
    // 
    //  
    [System.Security.SecurityCritical]
    internal void _Init(String path, int fAccess, FileShare share, UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs, FileIOPermissionAccess secAccess,
                        FileMode mode, int flagsAndAttributes, bool seekToEnd)
    { 
        String filePath = Path.GetFullPath(path);
        _fileName = filePath; 
 
        new FileIOPermission(secAccess, new String[] { filePath }).Demand();
 
        // Don't pop up a dialog for reading from an emtpy floppy drive
        int oldMode = UnsafeNativeMethods.SetErrorMode(UnsafeNativeMethods.SEM_FAILCRITICALERRORS);
        try {
            _handle = UnsafeNativeMethods.SafeCreateFile(filePath, fAccess, share, secAttrs, mode, flagsAndAttributes, UnsafeNativeMethods.NULL); 
            int errorCode = Marshal.GetLastWin32Error();
 
            if (_handle.IsInvalid) { 
                // Return a meaningful exception, using the RELATIVE path to
                // the file to avoid returning extra information to the caller 
                // unless they have path discovery permission, in which case
                // the full path is fine & useful.

                // We need to give an exception, and preferably it would include 
                // the fully qualified path name.  Do security check here.  If
                // we fail, give back the msgPath, which should not reveal much. 
                // While this logic is largely duplicated in 
                // __Error.WinIOError, we need this for
                // IsolatedStorageLogFileStream. 
                bool canGiveFullPath = false;

                try {
                    new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }).Demand(); 
                    canGiveFullPath = true;
                } 
                catch(SecurityException) {} 

                if (canGiveFullPath) 
                    __Error.WinIOError(errorCode, _fileName);
                else
                    __Error.WinIOError(errorCode, Path.GetFileName(_fileName));
            } 
        }
        finally { 
            UnsafeNativeMethods.SetErrorMode(oldMode); 
        }
        Debug.Assert(UnsafeNativeMethods.GetFileType(_handle) == UnsafeNativeMethods.FILE_TYPE_DISK, "did someone accidentally removed the device type check from SafeCreateFile P/Invoke wrapper?"); 

        pos = 0;

        // For Append mode... 
        if (seekToEnd) {
            SeekCore(0, SeekOrigin.End); 
        } 
    }
 
    public override bool CanRead {
        [Pure]
        get { return _canRead; }
    } 

    public override bool CanWrite { 
        [Pure] 
        get { return _canWrite; }
    } 

    public override bool CanSeek {
        [Pure]
        get { return _canSeek; } 
    }
 
    public override long Length { 
        get {
            throw new NotSupportedException(); 
        }
    }

    public override long Position { 
        get {
            throw new NotSupportedException(); 
        } 
        set {
            throw new NotSupportedException(); 
        }
    }

    public override void SetLength(long value) 
    {
        throw new NotSupportedException(); 
    } 

    public override long Seek(long offset, SeekOrigin origin) 
    {
        throw new NotSupportedException();
    }
 
    public override int Read(byte[] array, int offset, int count)
    { 
        throw new NotSupportedException(); 
    }
 
    // 
    // 
    // 
    //  
    // 
    [System.Security.SecurityCritical] 
    protected override unsafe void WriteCore(byte[] buffer, int offset, int count, bool blockForWrite, out long streamPos) { 
        Debug.Assert(CanWrite, "CanWrite");
        Debug.Assert(buffer != null, "buffer != null"); 
        Debug.Assert(offset >= 0, "offset is negative");
        Debug.Assert(count >= 0, "count is negative");

        int hr = 0; 
        int r = WriteFileNative(buffer, offset, count, null, out hr);
        if (r == -1) { 
            // For pipes, ERROR_NO_DATA is not an error, but the pipe is closing. 
            if (hr == UnsafeNativeMethods.ERROR_NO_DATA) {
                r = 0; 
            }
            else {
                // ERROR_INVALID_PARAMETER may be returned for writes
                // where the position is too large (ie, writing at Int64.MaxValue 
                // on Win9x) OR for synchronous writes to a handle opened
                // asynchronously. 
                if (hr == UnsafeNativeMethods.ERROR_INVALID_PARAMETER) 
                    throw new IOException(SR.GetString(SR.IO_FileTooLongOrHandleNotSync));
                __Error.WinIOError(hr, String.Empty); 
            }
        }
        Debug.Assert(r >= 0, "WriteCore is likely broken.");
        // update cached position 
        streamPos = AddUnderlyingStreamPosition((long)r);
        EnforceRetentionPolicy(_handle, streamPos); 
        streamPos = pos; 
        return;
    } 

    // 
    // 
    //  
    // 
    //  
    //  
    // 
    //  
    [System.Security.SecurityCritical]
    unsafe private int WriteFileNative(byte[] bytes, int offset, int count, NativeOverlapped* overlapped, out int hr) {
        if (_handle.IsClosed) __Error.FileNotOpen();
 
        if (_disableLogging) {
            hr = 0; 
            return 0; 
        }
 
        Debug.Assert(offset >= 0, "offset >= 0");
        Debug.Assert(count >= 0, "count >= 0");
        Debug.Assert(bytes != null, "bytes != null");
 
        // Don't corrupt memory when multiple threads are erroneously writing
        // to this stream simultaneously.  (the OS is reading from 
        // the array we pass to WriteFile, but if we read beyond the end and 
        // that memory isn't allocated, we could get an AV.)
        if (bytes.Length - offset < count) 
            throw new IndexOutOfRangeException(SR.GetString(SR.IndexOutOfRange_IORaceCondition));

        // You can't use the fixed statement on an array of length 0.
        if (bytes.Length==0) { 
            hr = 0;
            return 0; 
        } 

        int numBytesWritten = 0; 
        int r = 0;

        fixed(byte* p = bytes) {
            r = UnsafeNativeMethods.WriteFile(_handle, p + offset, count, out numBytesWritten, overlapped); 
        }
 
        if (r == 0) { 
            // We should never silently ---- an error here without some
            // extra work.  We must make sure that BeginWriteCore won't return an 
            // IAsyncResult that will cause EndWrite to block, since the OS won't
            // call AsyncFSCallback for us.
            hr = Marshal.GetLastWin32Error();
 
            // For invalid handles, detect the error and mark our handle
            // as closed to give slightly better error messages.  Also 
            // help ensure we avoid handle recycling bugs. 
            if (hr == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
                _handle.SetHandleAsInvalid(); 

            return -1;
        }
        else 
            hr = 0;
        return numBytesWritten; 
    } 

    // This doesn't do argument checking.  Necessary for SetLength, which must 
    // set the file pointer beyond the end of the file. This will update the
    // internal position
    // 
    //  
    // 
    //  
    //  
    // 
    [System.Security.SecurityCritical] 
    private long SeekCore(long offset, SeekOrigin origin)
    {
        Debug.Assert(!_handle.IsClosed, "!_handle.IsClosed");
        Debug.Assert(origin>=SeekOrigin.Begin && origin<=SeekOrigin.End, "origin>=SeekOrigin.Begin && origin<=SeekOrigin.End"); 
        int hr = 0;
        long ret = 0; 
 
        ret = UnsafeNativeMethods.SetFilePointer(_handle, offset, origin, out hr);
        if (ret == -1) { 
            // For invalid handles, detect the error and mark our handle
            // as closed to give slightly better error messages.  Also
            // help ensure we avoid handle recycling bugs.
            if (hr == UnsafeNativeMethods.ERROR_INVALID_HANDLE) 
                _handle.SetHandleAsInvalid();
            __Error.WinIOError(hr, String.Empty); 
        } 

        UnderlyingStreamPosition = ret; 
        return ret;
    }

    //  
    // 
    //  
    //  
    [System.Security.SecurityCritical]
    protected override void Dispose(bool disposing) 
    {
        // Nothing will be done differently based on whether we are
        // disposing vs. finalizing.  This is taking advantage of the
        // weak ordering between normal finalizable objects & critical 
        // finalizable objects, which I included in the SafeHandle
        // design for LogStream, which would often "just work" when 
        // finalized. 
        try {
            if (_handle == null || _handle.IsClosed) { 
                // Make sure BufferedStream doesn't try to flush data on a closed handle
                DiscardBuffer();
            }
        } 
        finally {
            try { 
                // Cleanup base streams 
                base.Dispose(disposing);
            } 
            finally {
                if (_handle != null && !_handle.IsClosed)
                    _handle.Dispose();
 
                _handle = null;
                _canRead = false; 
                _canWrite = false; 
                _canSeek = false;
            } 
        }
    }

    //  
    // 
    //  
    [System.Security.SecurityCritical] 
    ~LogStream()
    { 
        if (_handle != null) {
            Dispose(false);
        }
    } 

    //  
    //  
    // 
    //  
    // 
    [System.Security.SecurityCritical]
    private void EnforceRetentionPolicy(SafeFileHandle handle, long lastPos)
    { 
        switch (_retention) {
        case LogRetentionOption.LimitedSequentialFiles: 
        case LogRetentionOption.UnlimitedSequentialFiles: 
        case LogRetentionOption.LimitedCircularFiles:
            if ((lastPos >= _maxFileSize) && (handle == _handle)){ 
                lock (m_lockObject) {
                    if ((handle != _handle) || (lastPos < _maxFileSize))
                        return;
 
                    _currentFileNum++;
                    if ((_retention == LogRetentionOption.LimitedCircularFiles) && (_currentFileNum > _maxNumberOfFiles)) { 
                        _currentFileNum = 1; 
                    }
                    else if ((_retention == LogRetentionOption.LimitedSequentialFiles) && (_currentFileNum > _maxNumberOfFiles)) { 
                        _DisableLogging();
                        return;
                    }
 
                    if (_fileNameWithoutExt == null) {
                        _fileNameWithoutExt = Path.Combine(Path.GetDirectoryName(_pathSav), Path.GetFileNameWithoutExtension(_pathSav)); 
                        _fileExt = Path.GetExtension(_pathSav); 
                    }
 
                    string path = (_currentFileNum == 1)?_pathSav: _fileNameWithoutExt + _currentFileNum.ToString(CultureInfo.InvariantCulture) + _fileExt;
                    try {
                        _Init(path, _fAccessSav, _shareSav, _secAttrsSav, _secAccessSav, _modeSav, _flagsAndAttributesSav, _seekToEndSav);
 
                        // Dispose the old handle and release the file write lock
                        // No need to flush the buffer as we just came off a write 
                        if (handle != null && !handle.IsClosed) { 
                            handle.Dispose();
                        } 
                    }
                    catch (IOException ) {
                        // Should we do this only for ERROR_SHARING_VIOLATION?
                        //if (UnsafeNativeMethods.MakeErrorCodeFromHR(Marshal.GetHRForException(ioexc)) != InternalResources.ERROR_SHARING_VIOLATION) break; 

                        // Possible sharing violation - ----? Let the next iteration try again 
                        // For now revert the handle to the original one 
                        _handle = handle;
 
                        _retentionRetryCount++;
                        if (_retentionRetryCount >= _retentionRetryThreshold) {
                            _DisableLogging();
                        } 
#if DEBUG
                        throw; 
#endif 
                    }
                    catch (UnauthorizedAccessException ) { 
                        // Indicative of ACL issues
                        _DisableLogging();
#if DEBUG
                        throw; 
#endif
                    } 
                    catch (Exception ) { 
                        _DisableLogging();
#if DEBUG 
                        throw;
#endif
                    }
                } 
            }
            break; 
 
        case LogRetentionOption.SingleFileBoundedSize:
            if (lastPos >= _maxFileSize) 
                _DisableLogging();
            break;

        case LogRetentionOption.SingleFileUnboundedSize: 
            break;
        } 
    } 

    // When we enable this class widely, we need to raise an 
    // event when we disable logging due to rention policy or
    // error such as ACL that is preventing retention
    [MethodImplAttribute(MethodImplOptions.Synchronized)]
    private void _DisableLogging() 
    {
        // Discard write buffer? 
        _disableLogging = true; 
    }
 
    // 
    // 
    // 
    [System.Security.SecurityCritical] 
    private static UnsafeNativeMethods.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share)
    { 
        UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = null; 
        if ((share & FileShare.Inheritable) != 0) {
            secAttrs = new UnsafeNativeMethods.SECURITY_ATTRIBUTES(); 
            secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);

            secAttrs.bInheritHandle = 1;
        } 
        return secAttrs;
    } 
} 
}
 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK