StorageRoot.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 / wpf / src / Base / System / IO / Packaging / CompoundFile / StorageRoot.cs / 1305600 / StorageRoot.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  The root object for manipulating the WPP container. 
//
// History: 
//  05/10/2002: RogerCh: Initial creation.
//  06/12/2002: RogerCh: Catch & translate COMException from native calls.
//  06/25/2002: RogerCh: Add a constructor to build on top of IStorage.
//  06/28/2002: RogerCh: Add a boolean to avoid infinite loops in data space 
//               manager initialization.
//  07/31/2002: RogerCh: Make obvious that we are using security suppressed interfaces. 
//  05/20/2003: RogerCh: Ported to WCP tree. 
//
//----------------------------------------------------------------------------- 

using System;
using System.IO;
using System.Runtime.InteropServices; 

using System.Windows;    // For exception string lookup table 
 
using MS.Internal;                          // for Invariant
using MS.Internal.IO.Packaging.CompoundFile; 
using MS.Internal.WindowsBase;

namespace System.IO.Packaging
{ 

///  
/// The main container class, one instance per compound file 
/// 
internal  class StorageRoot : StorageInfo 
{
    /***********************************************************************/
    // Default values to use for the StorageRoot.Open shortcuts
    const FileMode   defaultFileMode   = FileMode.OpenOrCreate; 
    const FileAccess defaultFileAccess = FileAccess.ReadWrite;
    const FileShare  defaultFileShare  = FileShare.None; 
    const int        defaultSectorSize = 512; 
    const int        stgFormatDocFile  = 5; // STGFMT_DOCFILE
 
    /***********************************************************************/
    // Instance values

    ///  
    /// The reference to the IStorage root of this container.  This value
    /// is initialized at Open and zeroed out at Close.  If this value is 
    /// zero, it means the object has been disposed. 
    /// 
    IStorage rootIStorage; 

    /// 
    /// Cached instance to our data space manager
    ///  
    DataSpaceManager dataSpaceManager;
 
    ///  
    /// If we know we are in a read-only mode, we know not to do certain things.
    ///  
    bool containerIsReadOnly;

    /// 
    /// When data space manager is being initialized, sometimes it trips 
    /// actions that would (in other circumstances) require checking the
    /// data space manager.  To avoid an infinite loop, we break it by knowing 
    /// when data space manager is being initialized. 
    /// 
    bool dataSpaceManagerInitializationInProgress; 

    /***********************************************************************/
    private StorageRoot(IStorage root, bool readOnly )
        : base( root ) 
    {
        rootIStorage = root; 
        containerIsReadOnly = readOnly; 
        dataSpaceManagerInitializationInProgress = false;
    } 

    /// 
    /// The access mode available on this container
    ///  
    internal FileAccess OpenAccess
    { 
        get 
        {
            CheckRootDisposedStatus(); 
            if(containerIsReadOnly)
            {
                return FileAccess.Read;
            } 
            else
            { 
                return FileAccess.ReadWrite; 
            }
        } 
    }

    /// 
    /// Create a container StorageRoot based on the given System.IO.Stream object 
    /// 
    /// The new Stream upon which to build the new StorageRoot 
    /// New StorageRoot object built on the given Stream 
    internal static StorageRoot CreateOnStream( Stream baseStream )
    { 
        if (baseStream == null)
        {
            throw new ArgumentNullException("baseStream");
        } 

        if( 0 == baseStream.Length ) 
        { 
            return CreateOnStream( baseStream, FileMode.Create );
        } 
        else
        {
            return CreateOnStream( baseStream, FileMode.Open );
        } 
    }
 
    ///  
    /// Create a container StorageRoot based on the given System.IO.Stream object
    ///  
    /// The new Stream upon which to build the new StorageRoot
    /// The mode (Open or Create) to use on the lock bytes
    /// New StorageRoot object built on the given Stream
    internal static StorageRoot CreateOnStream(Stream baseStream, FileMode mode) 
    {
        if( null == baseStream ) 
            throw new ArgumentNullException("baseStream"); 

        IStorage storageOnStream; 
        int returnValue;
        int openFlags = SafeNativeCompoundFileConstants.STGM_SHARE_EXCLUSIVE;

        if( baseStream.CanRead ) 
        {
            if( baseStream.CanWrite ) 
            { 
                openFlags |= SafeNativeCompoundFileConstants.STGM_READWRITE;
            } 
            else
            {
                openFlags |= SafeNativeCompoundFileConstants.STGM_READ;
 
                if( FileMode.Create == mode )
                    throw new ArgumentException( 
                        SR.Get(SRID.CanNotCreateContainerOnReadOnlyStream)); 
            }
        } 
        else
        {
            throw new ArgumentException(
                SR.Get(SRID.CanNotCreateStorageRootOnNonReadableStream)); 
        }
 
        if( FileMode.Create == mode ) 
        {
            returnValue = SafeNativeCompoundFileMethods.SafeStgCreateDocfileOnStream( 
                baseStream,
                openFlags | SafeNativeCompoundFileConstants.STGM_CREATE,
                out storageOnStream);
        } 
        else if( FileMode.Open == mode )
        { 
            returnValue = SafeNativeCompoundFileMethods.SafeStgOpenStorageOnStream( 
                baseStream,
                openFlags, 
                out storageOnStream );
        }
        else
        { 
            throw new ArgumentException(
                SR.Get(SRID.CreateModeMustBeCreateOrOpen)); 
        } 

        switch( (uint) returnValue ) 
        {
            case SafeNativeCompoundFileConstants.S_OK:
                return StorageRoot.CreateOnIStorage(
                    storageOnStream ); 

            default: 
                throw new IOException( 
                    SR.Get(SRID.UnableToCreateOnStream),
                    new COMException( 
                        SR.Get(SRID.CFAPIFailure),
                        returnValue));
        }
    } 

    /// Open a container, given only the path. 
    /// Path to container file on local file system 
    /// StorageRoot instance representing the file
    internal static StorageRoot Open( 
        string path )
    {
        return Open( path, defaultFileMode, defaultFileAccess, defaultFileShare, defaultSectorSize );
    } 

    /// Open a container, given path and open mode 
    /// Path to container file on local file system 
    /// Access mode, see System.IO.FileMode in .NET SDK
    /// StorageRoot instance representing the file 
    internal static StorageRoot Open(
        string path,
        FileMode mode )
    { 
        return Open( path, mode, defaultFileAccess, defaultFileShare, defaultSectorSize );
    } 
 
    /// Open a container, given path, open mode, and access flag
    /// Path to container file on local file system 
    /// See System.IO.FileMode in .NET SDK
    /// See System.IO.FileAccess in .NET SDK
    /// StorageRoot instance representing the file
    internal static StorageRoot Open( 
        string path,
        FileMode mode, 
        FileAccess access ) 
    {
        return Open( path, mode, access, defaultFileShare, defaultSectorSize ); 
    }

    /// Open a container, given path, open mode, access flag, and sharing settings
    /// Path to container on local file system 
    /// See System.IO.FileMode in .NET SDK
    /// See System.IO.FileAccess in .NET SDK 
    /// See System.IO.FileSharing in .NET SDK 
    /// StorageRoot instance representing the file
    internal static StorageRoot Open( 
        string path,
        FileMode mode,
        FileAccess access,
        FileShare share ) 
    {
        return Open( path, mode, access, share, defaultSectorSize ); 
    } 
    /// Open a container given all the settings
    /// Path to container on local file system 
    /// See System.IO.FileMode in .NET SDK
    /// See System.IO.FileAccess in .NET SDK
    /// See System.IO.FileShare in .NET SDK
    /// Compound File sector size, must be 512 or 4096 
    /// StorageRoot instance representing the file
    internal static StorageRoot Open( 
        string path, 
        FileMode mode,
        FileAccess access, 
        FileShare share,
        int sectorSize )
    {
        int  grfMode = 0; 
        int  returnValue = 0;
 
        // Simple path validation 
        ContainerUtilities.CheckStringAgainstNullAndEmpty( path, "Path" );
 
        Guid IID_IStorage = new Guid(0x0000000B,0x0000,0x0000,0xC0,0x00,
                                     0x00,0x00,0x00,0x00,0x00,0x46);

        IStorage newRootStorage; 

        //////////////////////////////////////////////////////////////////// 
        // Generate STGM from FileMode 
        switch(mode)
        { 
            case FileMode.Append:
                throw new ArgumentException(
                    SR.Get(SRID.FileModeUnsupported));
            case FileMode.Create: 
                grfMode |= SafeNativeCompoundFileConstants.STGM_CREATE;
                break; 
            case FileMode.CreateNew: 
                {
                    FileInfo existTest = new FileInfo(path); 
                    if( existTest.Exists )
                    {
                        throw new IOException(
                            SR.Get(SRID.FileAlreadyExists)); 
                    }
                } 
                goto case FileMode.Create; 
            case FileMode.Open:
                break; 
            case FileMode.OpenOrCreate:
                {
                    FileInfo existTest = new FileInfo(path);
                    if( existTest.Exists ) 
                    {
                        // File exists, use open code path 
                        goto case FileMode.Open; 
                    }
                    else 
                    {
                        // File does not exist, use create code path
                        goto case FileMode.Create;
                    } 
                }
            case FileMode.Truncate: 
                throw new ArgumentException( 
                    SR.Get(SRID.FileModeUnsupported));
            default: 
                throw new ArgumentException(
                    SR.Get(SRID.FileModeInvalid));
        }
 
        // Generate the access flags from the access parameter
        SafeNativeCompoundFileMethods.UpdateModeFlagFromFileAccess( access, ref grfMode ); 
 
        // Generate STGM from FileShare
 
        // Note: the .NET SDK does not specify the proper behavior in reaction to
        //  incompatible flags being sent in together.  Should ArgumentException be
        //  thrown?  Or do some values "trump" others?
        if( 0 != (share & FileShare.Inheritable) ) 
        {
            throw new ArgumentException( 
                SR.Get(SRID.FileShareUnsupported)); 
        }
        else if( share == FileShare.None ) // FileShare.None is zero, using "&" to check causes unreachable code error 
        {
            grfMode |= SafeNativeCompoundFileConstants.STGM_SHARE_EXCLUSIVE;
        }
        else if( share == FileShare.Read ) 
        {
            grfMode |= SafeNativeCompoundFileConstants.STGM_SHARE_DENY_WRITE; 
        } 
        else if( share == FileShare.Write )
        { 
            grfMode |= SafeNativeCompoundFileConstants.STGM_SHARE_DENY_READ; // Note that this makes little sense when we don't support combination of flags
        }
        else if( share == FileShare.ReadWrite )
        { 
            grfMode |= SafeNativeCompoundFileConstants.STGM_SHARE_DENY_NONE;
        } 
        else 
        {
            throw new ArgumentException( 
                SR.Get(SRID.FileShareInvalid));
        }

        if( 0 != (grfMode & SafeNativeCompoundFileConstants.STGM_CREATE)) 
        {
            // STGM_CREATE set, call StgCreateStorageEx. 
            returnValue = SafeNativeCompoundFileMethods.SafeStgCreateStorageEx( 
                path,
                grfMode, 
                stgFormatDocFile,
                0,
                IntPtr.Zero,
                IntPtr.Zero, 
                ref IID_IStorage,
                out newRootStorage ); 
        } 
        else
        { 
            // STGM_CREATE not set, call StgOpenStorageEx.
            returnValue = SafeNativeCompoundFileMethods.SafeStgOpenStorageEx(
                path,
                grfMode, 
                stgFormatDocFile,
                0, 
                IntPtr.Zero, 
                IntPtr.Zero,
                ref IID_IStorage, 
                out newRootStorage );
        }

        switch( returnValue ) 
        {
            case SafeNativeCompoundFileConstants.S_OK: 
                return StorageRoot.CreateOnIStorage( 
                    newRootStorage );
            case SafeNativeCompoundFileConstants.STG_E_FILENOTFOUND: 
                throw new FileNotFoundException(
                    SR.Get(SRID.ContainerNotFound));
            case SafeNativeCompoundFileConstants.STG_E_INVALIDFLAG:
                throw new ArgumentException( 
                    SR.Get(SRID.StorageFlagsUnsupported),
                    new COMException( 
                        SR.Get(SRID.CFAPIFailure), 
                        returnValue));
            default: 
                throw new IOException(
                    SR.Get(SRID.ContainerCanNotOpen),
                    new COMException(
                        SR.Get(SRID.CFAPIFailure), 
                        returnValue));
        } 
    } 

    ///  
    /// Clean up this container storage instance
    /// 
    internal void Close()
    { 
        if( null == rootIStorage )
            return; // Extraneous calls to Close() are ignored 
 
        if( null != dataSpaceManager )
        { 
            // Tell data space manager to flush all information as necessary
            dataSpaceManager.Dispose();
            dataSpaceManager = null;
        } 

        try 
        { 
            // Shut down the underlying storage
            if( !containerIsReadOnly ) 
                rootIStorage.Commit(0);
        }
        finally
        { 
            // We need these clean up steps to run even if there's a problem
            //  with the commit above. 
            RecursiveStorageInfoCoreRelease( core ); 

            rootIStorage = null; 
        }
    }

    ///  
    /// Flush the storage root.
    ///  
    internal void Flush() 
    {
        CheckRootDisposedStatus(); 

        // Shut down the underlying storage
        if( !containerIsReadOnly )
            rootIStorage.Commit(0); 
    }
 
    ///  
    /// Obtains the data space manager object for this instance of the
    /// container.  Subsequent calls will return reference to the same 
    /// object.
    /// 
    /// Reference to the manager object
    internal DataSpaceManager GetDataSpaceManager() 
    {
        CheckRootDisposedStatus(); 
        if( null == dataSpaceManager ) 
        {
            if ( dataSpaceManagerInitializationInProgress ) 
                return null;  // initialization in progress - abort

            // Create new instance of data space manager
            dataSpaceManagerInitializationInProgress = true; 
            dataSpaceManager = new DataSpaceManager( this );
            dataSpaceManagerInitializationInProgress = false; 
        } 

        return dataSpaceManager; 
    }

    internal IStorage GetRootIStorage()
    { 
        return rootIStorage;
    } 
 
    // Check whether this StorageRoot class still has its underlying storage.
    //  If not, throw an object disposed exception.  This should be checked from 
    //  every non-static container external API.
    internal void CheckRootDisposedStatus()
    {
        if( RootDisposed ) 
            throw new ObjectDisposedException(null, SR.Get(SRID.StorageRootDisposed));
    } 
 
    // Check whether this StorageRoot class still has its underlying storage.
    internal bool RootDisposed 
    {
        get
        {
            return ( null == rootIStorage ); 
        }
    } 
 
    /// 
    /// This will create a container StorageRoot based on the given IStorage 
    /// interface
    /// 
    /// The new IStorage (RCW) upon which to build the new StorageRoot
    /// New StorageRoot object built on the given IStorage 
    private static StorageRoot CreateOnIStorage( IStorage root )
    { 
        // The root is created by calling unmanaged CompoundFile APIs. The return value from the call is always 
        //  checked to see if is S_OK. If it is S_OK, the root should never be null. However, just to make sure
        //  call Invariant.Assert 
        Invariant.Assert(root != null);

        System.Runtime.InteropServices.ComTypes.STATSTG rootSTAT;
        bool readOnly; 

        root.Stat( out rootSTAT, SafeNativeCompoundFileConstants.STATFLAG_NONAME ); 
 
        readOnly =( SafeNativeCompoundFileConstants.STGM_WRITE != ( rootSTAT.grfMode & SafeNativeCompoundFileConstants.STGM_WRITE ) &&
            SafeNativeCompoundFileConstants.STGM_READWRITE != (rootSTAT.grfMode & SafeNativeCompoundFileConstants.STGM_READWRITE) ); 

        return new StorageRoot( root, readOnly );
    }
} 
}
 

// 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