LogStore.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WCF / Log / System / IO / Log / LogStore.cs / 1305376 / 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.Runtime.Versioning;
    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")]
        [ResourceConsumption(ResourceScope.Machine)] 
        [ResourceExposure(ResourceScope.Machine)]
        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.
                        

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