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; }
}
}
}
|