FileController.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / TrustUi / MS / Internal / documents / Application / FileController.cs / 1 / FileController.cs

                            //------------------------------------------------------------------------------ 
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved. 
//
//  
// Responsible for the lifecycle of the FileDocument and the actions that can
// be performed on it. 
//  
//
// History: 
//  08/28/2005: [....]: Initial implementation.
//-----------------------------------------------------------------------------

using System; 
using System.IO;
using System.Security; 
using MS.Internal.Security; // AttachmentService 

namespace MS.Internal.Documents.Application 
{
/// 
/// Responsible for the lifecycle of the FileDocument and the actions that can
/// be performed on it. 
/// 
///  
internal class FileController : IDocumentController 
{
    #region IDocumentController Members 
    //-------------------------------------------------------------------------
    // IDocumentController Members
    //-------------------------------------------------------------------------
 
    /// 
    ///  
    ///  
    /// 
    /// Critical: 
    ///  - calls DocumentStream.CreateTemporary
    ///  - sets WorkspaceProxy with result DocumentStream.CreateTemporary
    /// TreatAsSafe:
    ///  - ensures CreateTemporary is called once (mitigates DoS) 
    ///  - value for WorkspaceProxy derives from SourceProxy which is critical
    ///    (safe value) 
    ///  
    [SecurityCritical, SecurityTreatAsSafe]
    bool IDocumentController.EnableEdit(Document document) 
    {
        FileDocument doc = (FileDocument)document;

        if (doc.WorkspaceProxy == null) 
        {
            // Try to obtain an exclusive lock on the source file. If this 
            // fails, we can still create a temporary file and Save As to a 
            // different location.
            bool canWriteToSource = doc.SourceProxy.ReOpenWriteable(); 

            DocumentManager documentManager = DocumentManager.CreateDefault();

            // We can save to the source file if we could reopen it for write 
            if (documentManager != null)
            { 
                documentManager.CanSave = canWriteToSource; 
            }
 
            doc.WorkspaceProxy = doc.SourceProxy.CreateTemporary(false);

            if (doc.WorkspaceProxy == null)
            { 
                FilePresentation.ShowNoTemporaryFileAccess();
            } 
        } 

        return (doc.WorkspaceProxy != null); 
    }

    /// 
    ///  
    /// 
    ///  
    /// Critical: 
    ///  - sets SourceProxy with result DocumentStream.Open
    ///  - calls critical InitializeCurrentDocumentProperties using critical Uri 
    /// TreatAsSafe:
    ///  - ensures Open is called once (mitigates DoS)
    ///  - value for SourceProxy derives from FileDocument.SourceToken
    ///    which is critical (safe value) 
    ///  - Uri is critical in DocumentProperties thus not leaked and critical in
    ///    Document (sourced from IE) thus safe for InitializeCurrentDocumentProperties 
    ///    although this extends the exposure of the Uri, this is by design as 
    ///    DocumentProperties uses it to display the value to the user who orginally
    ///    provided it (not leaked User to User) 
    /// 
    [SecurityCritical, SecurityTreatAsSafe]
    bool IDocumentController.Open(Document document)
    { 
        FileDocument doc = (FileDocument)document;
 
        if (doc.Source == null) 
        {
            try 
            {
                doc.SourceProxy = DocumentStream.Open(doc, false);
            }
            catch (UnauthorizedAccessException uae) 
            {
                FilePresentation.ShowNoAccessToSource(); 
                doc.SourceProxy = null; 

                Trace.SafeWrite( 
                    Trace.File,
                    "Unable to open specified location.\nException: {0}",
                    uae);
 
                return false;
            } 
            catch (IOException ioe) 
            {
                FilePresentation.ShowNoAccessToSource(); 
                doc.SourceProxy = null;

                Trace.SafeWrite(
                    Trace.File, 
                    "Unable to open specified location.\nException: {0}",
                    ioe); 
 
                return false;
            } 
        }

        DocumentProperties.InitializeCurrentDocumentProperties(doc.Uri);
 
        return true;
    } 
 
    /// 
    ///  
    /// 
    /// 
    /// Critical:
    ///  - sets SourceProxy which is critical 
    /// TreatAsSafe:
    ///  - SourceProxy's new value is null (which is safe) 
    ///  
    [SecurityCritical, SecurityTreatAsSafe]
    bool IDocumentController.Rebind(Document document) 
    {
        FileDocument doc = (FileDocument)document;
        if (doc.IsRebindNeeded)
        { 
            doc.SourceProxy.Close();
            doc.SourceProxy = null; 
 
            try
            { 
                doc.SourceProxy = DocumentStream.Open(doc, false);
            }
            catch (UnauthorizedAccessException uae)
            { 
                FilePresentation.ShowNoAccessToSource();
                doc.SourceProxy = null; 
 
                Trace.SafeWrite(
                    Trace.File, 
                    "Unable to reopen specified location.\nException: {0}",
                    uae);

                return false; 
            }
            catch (IOException ioe) 
            { 
                FilePresentation.ShowNoAccessToSource();
                doc.SourceProxy = null; 

                Trace.SafeWrite(
                    Trace.File,
                    "Unable to reopen specified location.\nException: {0}", 
                    ioe);
 
                return false; 
            }
        } 

        return true;
    }
 
    /// 
    ///  
    ///  
    /// 
    /// Critical: 
    ///  - accesses CriticalFileTokens
    ///  - sets DestinationProxy
    ///  - calls DocumentStream.CreateTemporary
    ///  - sets Document.IsDestinationIdenticalToSource 
    /// TreatAsSafe:
    ///  - only provides tokens to FilePresentation which is authorized by 
    ///    definition to disclose the information & to DocumentStream which 
    ///    does not leak them (safe from disclosure) & to StreamDocument which
    ///    also does not leak them 
    ///  - DestinationProxy is derived either from CriticalFileTokens or from
    ///    SourceProxy both are critical (safe value)
    ///  - DocumentStream.CreateTemporary is called only based on user
    ///    interaction or to update existing file (mitigates DoS) 
    ///  - Document.IsDestinationIdenticalToSource is set to the appropriate
    ///    value depending on whether or not the destination file is actually 
    ///    identical to the source file. We save the value of IsFileCopySafe to 
    ///    ensure that this does not change between where we determine the
    ///    appropriate action and where we actually take the action. 
    /// 
    [SecurityCritical, SecurityTreatAsSafe]
    bool IDocumentController.SaveAsPreperation(Document document)
    { 
        FileDocument doc = (FileDocument)document;
 
        CriticalFileToken sourceToken = doc.SourceToken; 
        CriticalFileToken saveToken = doc.DestinationToken;
 
        //----------------------------------------------------------------------
        // Get Save Location and Consent (if needed)

        bool haveConsent = false; 
        bool cancelSave = false;
 
        // Loop until we have consent to save to a file or the user cancels 
        while (!haveConsent && !cancelSave)
        { 
            // If we have a location, check to see if it is read-only
            if (saveToken != null)
            {
                if (DocumentStream.IsReadOnly(saveToken)) 
                {
                    // If the target file is read-only, we cannot save over it 
                    FilePresentation.ShowDestinationIsReadOnly(); 
                }
                else 
                {
                    // If the file isn't read-only, we now have consent to save
                    haveConsent = true;
                } 
            }
 
            if (!haveConsent) 
            {
                Trace.SafeWrite( 
                    Trace.File, "We don't have a save location, prompting user.");

                // by default set the same file
                if (saveToken == null) 
                {
                    saveToken = sourceToken; 
                } 

                // A false return value indicates that the user wanted to 
                // cancel the save
                cancelSave = !FilePresentation.ShowSaveFileDialog(ref saveToken);
            }
            else 
            {
                // Otherwise we do have consent to save to the location stored in 
                // the saveToken 
                doc.DestinationToken = saveToken;
            } 
        }

        // Validate: If still don't have consent return without saving
        if (!haveConsent) 
        {
            // ensure token is rescinded 
            doc.DestinationToken = null; 

            Trace.SafeWrite( 
                Trace.File,
                "{0} not handling we do not have user consent.",
                this);
 
            return false;
        } 
 
        bool isFileCopySafe = doc.IsFileCopySafe;
 
        //---------------------------------------------------------------------
        // Calculate Save Action
        SaveAction action = SaveAction.Unknown;
        if (doc.Source.CanWrite) 
        {
            action |= SaveAction.SourceIsWriteable; 
        } 
        if (sourceToken == saveToken)
        { 
            action |= SaveAction.TargetIsSelf;
        }
        if (isFileCopySafe)
        { 
            action |= SaveAction.CanCopyData;
        } 
 
        bool isDestinationIdentical = false;
 
        // Catch IO Exceptions; will return false and clear token
        try
        {
            //---------------------------------------------------------------------- 
            // Perform Optimal Save Action (see method remarks)
            switch (action) 
            { 
                // Example: We were successfully able to open the source package
                // for write and there were no RM changes. 
                // I/O Cost: Read & SafeWrite Changes
                case SaveAction.TargetIsSelf
                    | SaveAction.SourceIsWriteable
                    | SaveAction.CanCopyData: 

                    Trace.SafeWrite( 
                        Trace.File, 
                        "SaveAction {0}: Updating comparee to self.",
                        action); 

                    doc.DestinationProxy = doc.SourceProxy;
                    isDestinationIdentical = true;
                    break; 

                // Example: Another user / process had a lock on the file, however 
                // we would like to save now and there were no RM changes. 
                // I/O Cost: Varies (Read & SafeWrite Changes - Read & SafeWrite Sum)
                case SaveAction.TargetIsSelf | SaveAction.CanCopyData: 

                    Trace.SafeWrite(
                        Trace.File,
                        "SaveAction {0}: reopening editable, updating comparee to self.", 
                        action);
 
                    // re-open writeable if possible otherwise copy the file 
                    if (doc.SourceProxy.ReOpenWriteable())
                    { 
                        doc.DestinationProxy = doc.SourceProxy;
                        isDestinationIdentical = true;
                    }
                    else 
                    {
                        Trace.SafeWrite( 
                            Trace.File, 
                            "SaveAction {0}: creating a temporary document reopen failed.",
                            action); 

                        doc.DestinationProxy = doc.SourceProxy.CreateTemporary(true);
                        doc.SwapDestination = true;
                    } 
                    break;
 
                case SaveAction.TargetIsSelf | SaveAction.SourceIsWriteable: 
                case SaveAction.TargetIsSelf:
                    Trace.SafeWrite( 
                        Trace.File,
                        "SaveAction {0}: creating a temporary document.",
                        action);
                    doc.DestinationProxy = doc.SourceProxy.CreateTemporary(false); 
                    doc.SwapDestination = true;
                    break; 
 
                // Example: All other cases, like source is web based.
                // I/O Cost: Max (Read Sum & SafeWrite Sum) 
                default:
                    Trace.SafeWrite(
                        Trace.File,
                        "SaveAction {0}: Performing defaults.", 
                        action);
                    if (isFileCopySafe) 
                    { 
                        Trace.SafeWrite(
                            Trace.File, 
                            "SaveAction {0}: copying original document.",
                            action);
                        doc.DestinationProxy = doc.SourceProxy.Copy(saveToken);
                        isDestinationIdentical = true; 
                    }
                    else 
                    { 
                        doc.DestinationProxy = DocumentStream.Open(saveToken, true);
                        // ensure we have enough quota to be as large as the sum 
                        doc.DestinationProxy.SetLength(
                            doc.SourceProxy.Length +
                            (doc.WorkspaceProxy == null ? 0 : doc.WorkspaceProxy.Length));
                        // set it back as we don't do the copy 
                        doc.DestinationProxy.SetLength(0);
                    } 
                    doc.SwapDestination = false; 
                    break;
            } // switch (action) 

            // Set the IsDestinationIdenticalToSource flag on the document
            // depending on what happened above
            doc.IsDestinationIdenticalToSource = isDestinationIdentical; 

            return true; 
        } 
        catch (UnauthorizedAccessException uae)
        { 
            FilePresentation.ShowNoAccessToDestination();
            doc.DestinationProxy = null;
            // ensure token is recinded
            doc.DestinationToken = null; 

            Trace.SafeWrite( 
                Trace.File, 
                "SaveAction {0}: unable to open specified location.\nException: {1}",
                action, 
                uae);

            return false;
        } 
        catch (IOException ioe)
        { 
            FilePresentation.ShowNoAccessToDestination(); 
            doc.DestinationProxy = null;
            // ensure token is recinded 
            doc.DestinationToken = null;

            Trace.SafeWrite(
                Trace.File, 
                "SaveAction {0}: unable to set size at specified location.\nException: {1}",
                action, 
                ioe); 

            return false; 
        }
    }

    ///  
    /// 
    ///  
    ///  
    /// Critical:
    ///  - accesses & sets CriticalFileToken 
    ///  - sets Uri for document
    /// TreatAsSafe:
    ///  - checks if token is null and may use Location to set uri
    ///    (no leak of token) 
    ///  - sets token to null (safe data)
    ///  - document Uri is being set from CriticalFileToken (trusted data) 
    ///  
    [SecurityCritical, SecurityTreatAsSafe]
    bool IDocumentController.SaveCommit(Document document) 
    {
        bool success = true;
        FileDocument doc = (FileDocument)document;
        bool haveConsent = (doc.DestinationToken != null); 

        // Validate: If we have consent, if not return doing nothing. 
        if (!haveConsent) 
        {
            Trace.SafeWrite( 
                Trace.File,
                "{0}.SaveCommit handling but doing nothing we do not have user consent.",
                this);
 
            return true;
        } 
 
        doc.DestinationProxy.Flush();
 
        //----------------------------------------------------------------------
        // Swap Files if Needed

        if (doc.SwapDestination) 
        {
            if (doc.DestinationProxy.SwapWithOriginal()) 
            { 
                Trace.SafeWrite(
                    Trace.File, 
                    "SaveCommit has swapped Destination and Source file.");
            }
            else
            { 
                success = false;
                FilePresentation.ShowNoAccessToDestination(); 
                Trace.SafeWrite( 
                    Trace.File,
                    "SaveCommit did not succeed because a needed file swap failed."); 
            }

            // we attempted the operation turn off the request
            doc.SwapDestination = false; 
        }
 
        if (success) 
        {
            //----------------------------------------------------------------- 
            // Rebind / Reload the Document

            if (doc.SourceToken == doc.DestinationToken)
            { 
                // we changed the underlying data new keys may be required and
                // document policy may need re-evaluating or lost our reference 
                doc.IsRebindNeeded = true; 

                Trace.SafeWrite( 
                    Trace.File,
                    "SaveCommit declaring a rebind is needed.");
            }
            else 
            {
                Uri originalUri = doc.Uri; 
 
                // we are a new document and we should be reloaded
                doc.Uri = doc.DestinationToken.Location; 
                doc.IsReloadNeeded = true;
                // we are releasing our lock on the destination
                doc.DestinationProxy.Close();
                doc.DestinationProxy = null; 

                Trace.SafeWrite( 
                    Trace.File, 
                    "SaveCommit declaring a reload to {0} is needed.",
                    doc.Uri); 

                //------------------------------------------------------------------
                // Add Mark of Web
 
                // This only needs to be done when the DestinationToken is in a
                // different location from the SourceToken, and the equality 
                // operator on CriticalFileToken does properly compare the URI. 

                Trace.SafeWrite( 
                        Trace.File,
                        "AttachmentService.SaveWithUI from {0} to {1}.",
                        originalUri,
                        doc.DestinationToken.Location); 

                AttachmentService.SaveWithUI( 
                    IntPtr.Zero, originalUri, doc.DestinationToken.Location); 
            }
        } 

        // rescinding user consent as save is completed
        doc.DestinationToken = null;
        return success; 
    }
 
    ///  
    /// 
    ///  
    /// 
    /// Critical:
    ///  - accesses CriticalFileTokens
    /// TreatAsSafe: 
    ///  - we are saving the in memory document back to the local file
    ///    the token is being use for the same document 
    ///  
    [SecurityCritical, SecurityTreatAsSafe]
    bool IDocumentController.SavePreperation(Document document) 
    {
        FileDocument doc = (FileDocument)document;

        doc.DestinationToken = doc.SourceToken; 

        return ((IDocumentController)this).SaveAsPreperation(document); 
    } 

    #endregion IDocumentController Members 

    #region IChainOfResponsibiltyNode Members
    //-------------------------------------------------------------------------
    // IChainOfResponsibiltyNode Members 
    //-------------------------------------------------------------------------
 
    ///  
    /// 
    ///  
    bool IChainOfResponsibiltyNode.IsResponsible(Document subject)
    {
        return subject is FileDocument;
    } 

    #endregion IChainOfResponsibiltyNode Members 
 
    /// 
    /// Represents the type of save action to perform. 
    /// 
    [Flags]
    private enum SaveAction
    { 
        /// 
        /// Unsure what action to take. 
        ///  
        Unknown = 0,
        ///  
        /// The Destination document has the same location as the Source.
        /// 
        TargetIsSelf = 1,
        ///  
        /// The Source document was opened writeable.
        ///  
        SourceIsWriteable = 2, 
        /// 
        /// Copying the data at the file level is a safe operation. 
        /// 
        CanCopyData = 4
    }
} 
}

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