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 238
|
//------------------------------------------------------------------------------
// <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.")]
[SuppressMessage("Microsoft.Security.Xml", "CA3056: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 bug 791299)
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; }
}
}
}
|