LogStore.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / Log / System / IO / Log / LogStore.cs / 1 / LogStore.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.IO.Log
{ 
    using System;
    using System.Diagnostics; 
    using System.Globalization; 
    using System.IO;
    using System.Runtime.InteropServices; 
    using System.Security;
    using System.Security.AccessControl;
    using System.Security.Permissions;
    using System.Threading; 

    using Microsoft.Win32.SafeHandles; 
 
    [Flags]
    enum SequenceNumberConstraint 
    {
        None          = 0x00,
        CanBeInvalid  = 0x01,
        CanBeInactive = 0x02, 

        MustBeActive  = None, 
        Arbitrary     = CanBeInvalid | CanBeInactive 
    }
 
    public sealed class LogStore : IDisposable
    {
        const int GENERIC_READ = unchecked((int)0x80000000);
        const int GENERIC_WRITE = 0x40000000; 

        SafeFileHandle logFile; 
        bool archivable; 
        LogExtentCollection extents;
        LogManagementAsyncResult logManagement; 
        LogPolicy logPolicy;
        FileAccess access;

        public LogStore( 
            string path,
            FileMode mode) 
            : this(path, mode, FileAccess.ReadWrite) 
        {
        } 

        public LogStore(
            string path,
            FileMode mode, 
            FileAccess access)
            : this(path, mode, access, FileShare.None) 
        { 
        }
 
        public LogStore(
            string path,
            FileMode mode,
            FileAccess access, 
            FileShare share)
            : this(path, mode, access, share, null) 
        { 
        }
 

        [PermissionSetAttribute(SecurityAction.Demand, Name="FullTrust")]
        public LogStore(
            string path, 
            FileMode mode,
            FileAccess access, 
            FileShare share, 
            FileSecurity fileSecurity)
        { 
            Object pinningHandle = null;
            SECURITY_ATTRIBUTES secAttrs;

            try 
            {
 
                secAttrs = GetSecAttrs(share, fileSecurity, out pinningHandle); 

                this.access = access; 
                // Parameter conversion and validation
                //
                // We don't need FileShare.Inheritable anymore because we took
                // care of it in the security attributes. 
                //
                share &= ~FileShare.Inheritable; 
                ValidateParameters(path, mode, access, share); 

                // CLFS requires the path start with "log:". We'll 
                // just make sure that it does.
                //
                bool addLogPrefix = true;
                if (path.Length > 4) 
                {
                    if (0 == String.Compare(path, 
                                            0, 
                                            "log:",
                                            0, 
                                            4,
                                            StringComparison.OrdinalIgnoreCase))
                    {
                        addLogPrefix = false; 
                    }
                } 
 
                if (addLogPrefix)
                { 
                    path = "log:" + path;
                }

                int fAccess = 
                    (access == FileAccess.Read ? GENERIC_READ :
                    access == FileAccess.Write ? GENERIC_WRITE : 
                    GENERIC_READ | GENERIC_WRITE); 

                int flagsAndAttributes; 
                flagsAndAttributes = Const.FILE_FLAG_OVERLAPPED;

                try
                { 
                    this.logFile = UnsafeNativeMethods.CreateLogFile(
                        path, 
                        fAccess, 
                        share,
                        secAttrs, 
                        mode,
                        flagsAndAttributes);
                }
                catch(DllNotFoundException) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.PlatformNotSupported()); 
                } 

                bool throwing = true; 
                try
                {
                    bool writeOnly = (access & FileAccess.Read) == 0;
                    CommonInitialize(writeOnly); 
                    throwing = false;
                } 
                finally 
                {
                    if (throwing) 
                    {
                        this.logFile.Close();
                    }
                } 
            }
            finally 
            { 
                if (pinningHandle != null)
                { 
                    GCHandle pinHandle = (GCHandle)pinningHandle;
                    pinHandle.Free();
                }
            } 
        }
 
        [PermissionSetAttribute(SecurityAction.Demand, Name="FullTrust")] 
        public LogStore(SafeFileHandle handle)
        { 
            if (handle == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("handle"));

            this.logFile = handle; 

            CommonInitialize(false); 
        } 

        void CommonInitialize(bool writeOnly) 
        {
            if (!ThreadPool.BindHandle(this.logFile))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                    new IOException(SR.GetString(SR.IO_BindFailed)));
            } 
 
            this.logManagement = new LogManagementAsyncResult(this);
 
            if (!writeOnly)
            {
                CLFS_INFORMATION info;
                GetLogFileInformation(out info); 
                this.archivable = ((info.Attributes &
                                    Const.FILE_ATTRIBUTE_ARCHIVE) != 0); 
 
                this.extents = new LogExtentCollection(this);
                this.logPolicy = new LogPolicy(this); 
            }
        }

        public bool Archivable 
        {
            get 
            { 
                return this.archivable;
            } 

            set
            {
                CLFS_LOG_ARCHIVE_MODE archiveMode; 
                archiveMode =
                    (value ? 
                     CLFS_LOG_ARCHIVE_MODE.ClfsLogArchiveEnabled : 
                     CLFS_LOG_ARCHIVE_MODE.ClfsLogArchiveDisabled);
                UnsafeNativeMethods.SetLogArchiveMode(this.logFile, 
                                                      archiveMode);

                this.archivable = value;
            } 
        }
 
        public SequenceNumber BaseSequenceNumber 
        {
            get 
            {
                CLFS_INFORMATION info;
                GetLogFileInformation(out info);
 
                return new SequenceNumber(info.BaseLsn);
            } 
        } 

        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] 
        public static void Delete(
            string path)
        {
            // Parameter conversion and validation 

            if(string.IsNullOrEmpty(path)) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("path"));
            } 

            // CLFS requires the path start with "log:". We'll
            // just make sure that it does.
            // 
            bool addLogPrefix = true;
            if (path.Length > 4) 
            { 
                if (0 == String.Compare(path,
                                        0, 
                                        "log:",
                                        0,
                                        4,
                                        StringComparison.OrdinalIgnoreCase)) 
                {
                    addLogPrefix = false; 
                } 
            }
 
            if (addLogPrefix)
            {
                path = "log:" + path;
            } 

            try 
            { 
                UnsafeNativeMethods.DeleteLogFile(path, null);
            } 
            catch(DllNotFoundException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.PlatformNotSupported());
            } 
        }
 
        public LogExtentCollection Extents 
        {
            get { return this.extents; } 
        }

        public long FreeBytes
        { 
            get
            { 
                CLFS_INFORMATION info; 
                GetLogFileInformation(out info);
 
                // This is just a little thing to make the estimate
                // more accurate. If we say 10 bytes free, you ought
                // to be able to append a 10 byte record.
                // If we have less space free than what a header requires, 
                // you can't append anything more so we return zero.
                // 
                long freeBytes = checked((long)info.CurrentAvailable); 
                if (freeBytes > LogLogRecordHeader.Size)
                    freeBytes -= LogLogRecordHeader.Size; 
                else
                    freeBytes = 0;

                return freeBytes; 
            }
        } 
 
        public SafeFileHandle Handle
        { 
            get { return this.logFile; }
        }

        public SequenceNumber LastSequenceNumber 
        {
            get 
            { 
                CLFS_INFORMATION info;
                GetLogFileInformation(out info); 

                return new SequenceNumber(info.LastLsn);
            }
        } 

        public long Length 
        { 
            get
            { 
                CLFS_INFORMATION info;
                GetLogFileInformation(out info);

                return checked((long)info.TotalAvailable); 
            }
        } 
 
        internal LogManagementAsyncResult LogManagement
        { 
            get { return this.logManagement; }
        }

        public int StreamCount 
        {
            get 
            { 
                CLFS_INFORMATION info;
                GetLogFileInformation(out info); 

                return checked((int)info.TotalClients);
            }
        } 

        public LogPolicy Policy 
        { 
            get
            { 
                return this.logPolicy;
            }
        }
 
        internal object SyncRoot
        { 
            get 
            {
                return this.logManagement; 
            }
        }

        internal FileAccess Access 
        {
            get 
            { 
                return this.access;
            } 
        }

        public LogArchiveSnapshot CreateLogArchiveSnapshot()
        { 
            return CreateLogArchiveSnapshot(
                SequenceNumber.Invalid, 
                SequenceNumber.Invalid); 
        }
 
        public LogArchiveSnapshot CreateLogArchiveSnapshot(
            SequenceNumber first,
            SequenceNumber last)
        { 

            ValidateSequenceNumber( 
                ref first, 
                SequenceNumberConstraint.CanBeInvalid,
                "first"); 
            ValidateSequenceNumber(
                ref last,
                SequenceNumberConstraint.CanBeInvalid,
                "last"); 
            if (!this.archivable)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotArchivable()); 
            }
 
            ulong lsnStart = first.High;
            ulong lsnEnd = last.High;

            if ((first == SequenceNumber.Invalid) || 
                (last == SequenceNumber.Invalid))
            { 
                CLFS_INFORMATION logInfo; 
                GetLogFileInformation(out logInfo);
 
                if (first == SequenceNumber.Invalid)
                {
                    lsnStart = Math.Min(logInfo.BaseLsn,
                                        logInfo.MinArchiveTailLsn); 
                }
 
                if (last == SequenceNumber.Invalid) 
                {
                    lsnEnd = logInfo.LastLsn; 
                }
            }

            if (lsnStart > lsnEnd) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.Argument_SnapshotBoundsInvalid)); 
            } 

            return new LogArchiveSnapshot(this, lsnStart, lsnEnd); 
        }

        public void Dispose()
        { 
            if (!this.logFile.IsInvalid)
            { 
                this.logFile.Close(); 
            }
        } 

        public void SetArchiveTail(SequenceNumber archiveTail)
        {
            ValidateSequenceNumber( 
                ref archiveTail,
                SequenceNumberConstraint.MustBeActive, 
                "archiveTail"); 
            if (!this.archivable)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotArchivable());
            }

            ulong sequence = archiveTail.High; 
            UnsafeNativeMethods.SetLogArchiveTailSync(
                this.logFile, 
                ref sequence); 
        }
 
        internal void GetLogFileInformation(out CLFS_INFORMATION pinfoBuffer)
        {
            pinfoBuffer = new CLFS_INFORMATION();
 
            int size = Marshal.SizeOf(typeof(CLFS_INFORMATION));
            UnsafeNativeMethods.GetLogFileInformation( 
                this.logFile, 
                ref pinfoBuffer,
                ref size); 
        }

        internal void ValidateSequenceNumber(
            ref SequenceNumber sequenceNumber, 
            SequenceNumberConstraint constraint,
            string paramName) 
        { 
            if (sequenceNumber == SequenceNumber.Invalid)
            { 
                if ((constraint & SequenceNumberConstraint.CanBeInvalid) != 0)
                {
                    return;
                } 
                else
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.SequenceNumberNotActive(paramName)); 
                }
            } 

            if (sequenceNumber.Low != 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.SequenceNumberInvalid()); 
            }
 
            if ((constraint & SequenceNumberConstraint.CanBeInactive) == 0) 
            {
                CLFS_INFORMATION info; 
                GetLogFileInformation(out info);

                ulong lsn = sequenceNumber.High;
                if (lsn < info.BaseLsn || lsn > info.LastLsn) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.SequenceNumberNotActive(paramName)); 
                } 
            }
        } 

        // If pinningHandle is not null, caller must free it AFTER the call to
        // CreateFile has returned.
        // 
        // [....]: Copied this from System.IO.FileStream
        // 
        private static unsafe SECURITY_ATTRIBUTES GetSecAttrs( 
            FileShare share,
            FileSecurity fileSecurity, 
            out object pinningHandle)
        {
            pinningHandle = null;
            SECURITY_ATTRIBUTES secAttrs = null; 
            if ((share & FileShare.Inheritable) != 0 || fileSecurity != null)
            { 
                secAttrs = new SECURITY_ATTRIBUTES(); 
                secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
 
                if ((share & FileShare.Inheritable) != 0)
                {
                    secAttrs.bInheritHandle = 1;
                } 

                // For ACLs, get the security descriptor from the FileSecurity. 
                if (fileSecurity != null) 
                {
                    byte[] sd = fileSecurity.GetSecurityDescriptorBinaryForm(); 
                    pinningHandle = GCHandle.Alloc(sd, GCHandleType.Pinned);
                    fixed (byte* pSecDescriptor = sd)
                        secAttrs.pSecurityDescriptor = pSecDescriptor;
                } 
            }
            return secAttrs; 
        } 

        private static void ValidateParameters( 
            string path,
            FileMode mode,
            FileAccess access,
            FileShare share) 
        {
            if(string.IsNullOrEmpty(path)) 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("path")); 

            if (!((mode == FileMode.CreateNew) || 
                  (mode == FileMode.Open) ||
                  (mode == FileMode.OpenOrCreate)))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("mode")); 
            }
 
            if (access < FileAccess.Read || access > FileAccess.ReadWrite) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("access")); 
            }

            if (share < FileShare.None || share > (FileShare.ReadWrite | FileShare.Delete))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("share"));
            } 
 
            if ((mode == FileMode.CreateNew) && ((access & FileAccess.Write) == 0))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.Argument_CreateNewNoWrite));
            }
            if((mode == FileMode.OpenOrCreate) && ((access & FileAccess.Write) == 0))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.Argument_OpenOrCreateNoWrite));
            } 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

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