Welcome to mirror list, hosted at ThFree Co, Russian Federation.

PreservationFileReader.cs « Compilation « System.Web « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 956ea7082a209676e6f2676a65f9c8a2e60810b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
//------------------------------------------------------------------------------
// <copyright file="PreservationFileReader.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------



namespace System.Web.Compilation {

using System;
using System.IO;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Xml;
using System.Security;
using System.Web.Configuration;
using System.Web.Util;
using System.Web.UI;

internal class PreservationFileReader {

    private XmlNode _root;
    private bool _precompilationMode;
    private DiskBuildResultCache _diskCache;

    private ArrayList _sourceDependencies;

    internal PreservationFileReader(DiskBuildResultCache diskCache, bool precompilationMode) {
        _diskCache = diskCache;
        _precompilationMode = precompilationMode;
    }

    internal BuildResult ReadBuildResultFromFile(VirtualPath virtualPath, string preservationFile, long hashCode, bool ensureIsUpToDate) {

        // Ignore if the preservation file doesn't exist
        if (!FileUtil.FileExists(preservationFile)) {
            Debug.Trace("PreservationFileReader", "Can't find preservation file " + Path.GetFileName(preservationFile));
            return null;
        }

        BuildResult result = null;
        try {
            result = ReadFileInternal(virtualPath, preservationFile, hashCode, ensureIsUpToDate);
        }
        catch (SecurityException) {
            // We eat all exceptions, except for SecurityException's, because they
            // are ususally a sign that something is not set up correctly, and we
            // don't want to lose the stack (VSWhidbey 269566)
            throw;
        }
        catch {
            if (!_precompilationMode) {
                // The preservation file can't be used, so get rid of it
                Util.RemoveOrRenameFile(preservationFile);
            }
        }

        return result;
    }

    [SuppressMessage("Microsoft.Security", "MSEC1207:UseXmlReaderForLoad", Justification = "Xml file is created by us and only accessible to admins.")]
    private BuildResult ReadFileInternal(VirtualPath virtualPath, string preservationFile, long hashCode, bool ensureIsUpToDate) {

        XmlDocument doc = new XmlDocument();

        doc.Load(preservationFile);

        // Get the root element, and make sure it's what we expect
        _root = doc.DocumentElement;
        Debug.Assert(_root != null && _root.Name == "preserve", "_root != null && _root.Name == \"preserve\"");
        if (_root == null || _root.Name != "preserve")
            return null;

        // Get the type of the BuildResult preserved in this file
        string resultTypeCodeString = GetAttribute("resultType");
        BuildResultTypeCode resultTypeCode = (BuildResultTypeCode)Int32.Parse(
            resultTypeCodeString, CultureInfo.InvariantCulture);

        // Get the config path that affects this BuildResult if one wasn't passed in.
        // Note that the passed in path may be different with Sharepoint-like ghosting (VSWhidbey 343230)
        if (virtualPath == null)
            virtualPath = VirtualPath.Create(GetAttribute("virtualPath"));

        long savedHash = 0;
        string savedFileHash = null;

        // Ignore dependencies in precompilation mode
        if (!_precompilationMode) {
            // Read the saved hash from the preservation file
            string hashString = GetAttribute("hash");
            Debug.Assert(hashString != null, "hashString != null");
            if (hashString == null)
                return null;

            // Parse the saved hash string as an hex int
            savedHash = Int64.Parse(hashString, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);

            // Read the saved file hash from the preservation file.  This is the hash the represents
            // the state of all the virtual files that the build result depends on.
            savedFileHash = GetAttribute("filehash");
        }

        // Create the BuildResult accordingly
        BuildResult result = BuildResult.CreateBuildResultFromCode(resultTypeCode, virtualPath);

        // Ignore dependencies in precompilation mode
        if (!_precompilationMode) {

            ReadDependencies();
            if (_sourceDependencies != null)
                result.SetVirtualPathDependencies(_sourceDependencies);

            result.VirtualPathDependenciesHash = savedFileHash;

            // Check if the build result is up to date
            bool outOfDate = false;
            if (!result.IsUpToDate(virtualPath, ensureIsUpToDate)) {
                Debug.Trace("PreservationFileReader", Path.GetFileName(preservationFile) +
                    " is out of date (IsUpToDate==false)");

                outOfDate = true;
            }
            else {

                // The virtual paths hash code was up to date, so check the
                // other hash code.

                // Get the current hash code
                long currentHash = result.ComputeHashCode(hashCode);

                // If the hash doesn't match, the preserved data is out of date
                if (currentHash == 0 || currentHash != savedHash) {
                    outOfDate = true;
                    Debug.Trace("PreservationFileReader", Path.GetFileName(preservationFile) +
                        " is out of date (ComputeHashCode)");
                }
            }

            if (outOfDate) {
                bool gotLock = false;
                try {
                    // We need to delete the preservation file together with the assemblies/pdbs
                    // under the same lock so to avoid bad interleaving where one process 
                    // deletes the .compiled file that another process just created, orphaning
                    // the files generated by the other process. 
                    // (Dev10 
                    CompilationLock.GetLock(ref gotLock);

                    // Give the BuildResult a chance to do some cleanup
                    result.RemoveOutOfDateResources(this);

                    // The preservation file is not useable, so delete it
                    File.Delete(preservationFile);
                }
                finally {
                    // Always release the mutex if we had taken it
                    if (gotLock) {
                        CompilationLock.ReleaseLock();
                    }
                }
                return null;
            }
        }

        // Ask the BuildResult to read the data it needs
        result.GetPreservedAttributes(this);

        return result;
    }

    private void ReadDependencies() {

        IEnumerator childEnumerator = _root.ChildNodes.GetEnumerator();
        while (childEnumerator.MoveNext()) {
            XmlNode dependenciesNode = (XmlNode)childEnumerator.Current;
            if (dependenciesNode.NodeType != XmlNodeType.Element)
                continue;

            // verify no unrecognized attributes
            Debug.Assert(dependenciesNode.Attributes.Count == 0); 

            switch (dependenciesNode.Name) {
            case PreservationFileWriter.fileDependenciesTagName:
                Debug.Assert(_sourceDependencies == null);
                _sourceDependencies = ReadDependencies(dependenciesNode,
                    PreservationFileWriter.fileDependencyTagName);
                break;

            default:
                Debug.Assert(false, dependenciesNode.Name);
                break;
            }
        }
    }

    private ArrayList ReadDependencies(XmlNode parent, string tagName) {

        ArrayList dependencies = new ArrayList();

        IEnumerator childEnumerator = parent.ChildNodes.GetEnumerator();
        while (childEnumerator.MoveNext()) {
            XmlNode dependencyNode = (XmlNode)childEnumerator.Current;
            if (dependencyNode.NodeType != XmlNodeType.Element)
                continue;

            Debug.Assert(dependencyNode.Name.Equals(tagName));
            if (!dependencyNode.Name.Equals(tagName))
                break;

            string fileName = HandlerBase.RemoveAttribute(dependencyNode, "name");

            Debug.Assert(fileName != null, "fileName != null");

            // verify no unrecognized attributes
            Debug.Assert(dependencyNode.Attributes.Count == 0); 

            if (fileName == null)
                return null;

            dependencies.Add(fileName);
        }

        return dependencies;
    }

    internal string GetAttribute(string name) {
        return HandlerBase.RemoveAttribute(_root, name);
    }

    internal DiskBuildResultCache DiskCache {
        get { return _diskCache; }
    }
}

}