File: System\IO\Log\LogArchiveSnapshot.cs
Project: ndp\cdf\src\NetFx35\System.IO.Log\System.IO.Log.csproj (System.IO.Log)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.IO.Log
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using System.Text;
 
    public sealed class LogArchiveSnapshot
    {
        SequenceNumber archiveTail;
        SequenceNumber baseSequenceNumber;
        SequenceNumber lastSequenceNumber;
 
        IEnumerable<FileRegion> regions;
 
        const int MaxFileNameLength = 260;
 
        internal LogArchiveSnapshot(LogStore store,
                                    ulong lsnLow,
                                    ulong lsnHigh)
        {
            StringBuilder baseLogFileName = new StringBuilder(MaxFileNameLength);
            int actualLength;
            ulong baseLogFileOffset;
            ulong baseLogFileLength;
            ulong lsnBase;
            ulong lsnLast;
            ulong lsnArchiveTail;
 
            SafeArchiveContext archiveContext = null;
            try
            {
                while (!UnsafeNativeMethods.PrepareLogArchive(
                        store.Handle,
                        baseLogFileName,
                        baseLogFileName.Capacity,
                        ref lsnLow,
                        ref lsnHigh,
                        out actualLength,
                        out baseLogFileOffset,
                        out baseLogFileLength,
                        out lsnBase,
                        out lsnLast,
                        out lsnArchiveTail,
                        out archiveContext))
                {
                    baseLogFileName.EnsureCapacity(actualLength + 1);
                }
 
                this.archiveTail = new SequenceNumber(lsnArchiveTail);
                this.baseSequenceNumber = new SequenceNumber(lsnBase);
                this.lastSequenceNumber = new SequenceNumber(lsnLast);
 
                List<FileRegion> regions = new List<FileRegion>();
 
                byte[] readBuffer = new byte[checked((uint)baseLogFileLength)];
                uint actualDataLength = 0;
                unsafe
                {
                    fixed (byte* pbReadBuffer = readBuffer)
                    {
                        UnsafeNativeMethods.ReadLogArchiveMetadata(
                            archiveContext,
                            0,
                            readBuffer.Length,
                            pbReadBuffer,
                            out actualDataLength);
                    }
                }
 
                byte[] baseFileData;
                if (actualDataLength == (uint)baseLogFileLength)
                {
                    baseFileData = readBuffer;
                }
                else
                {
                    baseFileData = new byte[actualDataLength];
                    Array.Copy(readBuffer, baseFileData, baseFileData.Length);
                }
                regions.Add(new FileRegion((long)baseLogFileLength,
                                           baseLogFileName.ToString(),
                                           (long)baseLogFileOffset,
                                           baseFileData));
 
 
                CLFS_ARCHIVE_DESCRIPTOR descriptor = new CLFS_ARCHIVE_DESCRIPTOR();
                while (true)
                {
                    int returnedCount;
                    if (!UnsafeNativeMethods.GetNextLogArchiveExtentSingle(
                            archiveContext,
                            ref descriptor,
                            out returnedCount))
                    {
                        break;
                    }
 
                    if (returnedCount < 1) break;
 
                    long start = checked((long)descriptor.coffLow);
                    long length = checked((long)(descriptor.coffHigh - descriptor.coffLow));
                    string fileName = descriptor.infoContainer.GetActualFileName(store.Handle);
 
                    FileInfo containerInfo;
                    containerInfo = new FileInfo(fileName);
 
                    regions.Add(new FileRegion(containerInfo.Length,
                                               fileName,
                                               start,
                                               length));
                }
 
                this.regions = regions.AsReadOnly();
            }
            finally
            {
                if (archiveContext != null && !archiveContext.IsInvalid)
                {
                    archiveContext.Close();
                }
            }
        }
 
        public IEnumerable<FileRegion> ArchiveRegions
        {
            get
            {
                return this.regions;
            }
        }
 
        public SequenceNumber ArchiveTail
        {
            get
            {
                return this.archiveTail;
            }
        }
 
        public SequenceNumber BaseSequenceNumber
        {
            get
            {
                return this.baseSequenceNumber;
            }
        }
 
        public SequenceNumber LastSequenceNumber
        {
            get
            {
                return this.lastSequenceNumber;
            }
        }
    }
}