1 //------------------------------------------------------------------------------ 2 // <copyright file="TempFiles.cs" company="Microsoft"> 3 // 4 // <OWNER>Microsoft</OWNER> 5 // Copyright (c) Microsoft Corporation. All rights reserved. 6 // </copyright> 7 //------------------------------------------------------------------------------ 8 9 namespace System.CodeDom.Compiler { 10 using System; 11 using System.Collections; 12 using System.Diagnostics; 13 using System.IO; 14 using System.Runtime.InteropServices; 15 using System.Text; 16 using Microsoft.Win32; 17 using System.Security; 18 using System.Security.Permissions; 19 using System.Security.Principal; 20 using System.ComponentModel; 21 using System.Security.Cryptography; 22 using System.Globalization; 23 using System.Runtime.Versioning; 24 25 /// <devdoc> 26 /// <para>Represents a collection of temporary file names that are all based on a 27 /// single base filename located in a temporary directory.</para> 28 /// </devdoc> 29 [PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")] 30 [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")] 31 [Serializable] 32 public class TempFileCollection : ICollection, IDisposable { 33 string basePath; 34 string tempDir; 35 bool keepFiles; 36 Hashtable files; 37 38 /// <devdoc> 39 /// <para>[To be supplied.]</para> 40 /// </devdoc> TempFileCollection()41 public TempFileCollection() : this(null, false) { 42 } 43 44 /// <devdoc> 45 /// <para>[To be supplied.]</para> 46 /// </devdoc> TempFileCollection(string tempDir)47 public TempFileCollection(string tempDir) : this(tempDir, false) { 48 } 49 50 /// <devdoc> 51 /// <para>[To be supplied.]</para> 52 /// </devdoc> TempFileCollection(string tempDir, bool keepFiles)53 public TempFileCollection(string tempDir, bool keepFiles) { 54 this.keepFiles = keepFiles; 55 this.tempDir = tempDir; 56 #if !FEATURE_CASE_SENSITIVE_FILESYSTEM 57 files = new Hashtable(StringComparer.OrdinalIgnoreCase); 58 #else 59 files = new Hashtable(); 60 #endif 61 } 62 63 /// <internalonly/> 64 /// <devdoc> 65 /// <para> To allow it's stuff to be cleaned up</para> 66 /// </devdoc> IDisposable.Dispose()67 void IDisposable.Dispose() { 68 Dispose(true); 69 GC.SuppressFinalize(this); 70 } Dispose(bool disposing)71 protected virtual void Dispose(bool disposing) { 72 // It is safe to call Delete from here even if Dispose is called from Finalizer 73 // because the graph of objects is guaranteed to be there and 74 // neither Hashtable nor String have a finalizer of their own that could 75 // be called before TempFileCollection Finalizer 76 Delete(); 77 } 78 79 /// <devdoc> 80 /// <para>[To be supplied.]</para> 81 /// </devdoc> ~TempFileCollection()82 ~TempFileCollection() { 83 Dispose(false); 84 } 85 86 /// <devdoc> 87 /// <para>[To be supplied.]</para> 88 /// </devdoc> AddExtension(string fileExtension)89 public string AddExtension(string fileExtension) { 90 return AddExtension(fileExtension, keepFiles); 91 } 92 93 /// <devdoc> 94 /// <para>[To be supplied.]</para> 95 /// </devdoc> AddExtension(string fileExtension, bool keepFile)96 public string AddExtension(string fileExtension, bool keepFile) { 97 if (fileExtension == null || fileExtension.Length == 0) 98 throw new ArgumentException(SR.GetString(SR.InvalidNullEmptyArgument, "fileExtension"), "fileExtension"); // fileExtension not specified 99 string fileName = BasePath + "." + fileExtension; 100 AddFile(fileName, keepFile); 101 return fileName; 102 } 103 104 /// <devdoc> 105 /// <para>[To be supplied.]</para> 106 /// </devdoc> AddFile(string fileName, bool keepFile)107 public void AddFile(string fileName, bool keepFile) { 108 if (fileName == null || fileName.Length == 0) 109 throw new ArgumentException(SR.GetString(SR.InvalidNullEmptyArgument, "fileName"), "fileName"); // fileName not specified 110 111 if (files[fileName] != null) 112 throw new ArgumentException(SR.GetString(SR.DuplicateFileName, fileName), "fileName"); // duplicate fileName 113 files.Add(fileName, (object)keepFile); 114 } 115 116 /// <devdoc> 117 /// <para>[To be supplied.]</para> 118 /// </devdoc> GetEnumerator()119 public IEnumerator GetEnumerator() { 120 return files.Keys.GetEnumerator(); 121 } 122 123 /// <internalonly/> IEnumerable.GetEnumerator()124 IEnumerator IEnumerable.GetEnumerator() { 125 return files.Keys.GetEnumerator(); 126 } 127 128 /// <internalonly/> ICollection.CopyTo(Array array, int start)129 void ICollection.CopyTo(Array array, int start) { 130 files.Keys.CopyTo(array, start); 131 } 132 133 /// <devdoc> 134 /// <para>[To be supplied.]</para> 135 /// </devdoc> CopyTo(string[] fileNames, int start)136 public void CopyTo(string[] fileNames, int start) { 137 files.Keys.CopyTo(fileNames, start); 138 } 139 140 /// <devdoc> 141 /// <para>[To be supplied.]</para> 142 /// </devdoc> 143 public int Count { 144 get { 145 return files.Count; 146 } 147 } 148 149 /// <internalonly/> 150 int ICollection.Count { 151 get { return files.Count; } 152 } 153 154 /// <internalonly/> 155 object ICollection.SyncRoot { 156 get { return null; } 157 } 158 159 /// <internalonly/> 160 bool ICollection.IsSynchronized { 161 get { return false; } 162 } 163 164 /// <devdoc> 165 /// <para>[To be supplied.]</para> 166 /// </devdoc> 167 public string TempDir { 168 get { return tempDir == null ? string.Empty : tempDir; } 169 } 170 171 /// <devdoc> 172 /// <para>[To be supplied.]</para> 173 /// </devdoc> 174 public string BasePath { 175 get { 176 EnsureTempNameCreated(); 177 return basePath; 178 } 179 } 180 181 [ResourceExposure(ResourceScope.None)] 182 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] EnsureTempNameCreated()183 void EnsureTempNameCreated() { 184 if (basePath == null) { 185 186 string tempFileName = null; 187 FileStream tempFileStream; 188 bool uniqueFile = false; 189 int retryCount = 5000; 190 do { 191 try { 192 basePath = GetTempFileName(TempDir); 193 194 string full = Path.GetFullPath(basePath); 195 196 new FileIOPermission(FileIOPermissionAccess.AllAccess, full).Demand(); 197 198 // make sure the filename is unique. 199 tempFileName = basePath + ".tmp"; 200 using (tempFileStream = new FileStream(tempFileName, FileMode.CreateNew, FileAccess.Write)) { } 201 uniqueFile = true; 202 } 203 catch (IOException e) { 204 retryCount--; 205 206 uint HR_ERROR_FILE_EXISTS = unchecked(((uint)0x80070000) | NativeMethods.ERROR_FILE_EXISTS); 207 if (retryCount == 0 || Marshal.GetHRForException(e) != HR_ERROR_FILE_EXISTS) 208 throw; 209 210 uniqueFile = false; 211 } 212 }while (!uniqueFile); 213 files.Add(tempFileName, keepFiles); 214 215 } 216 } 217 218 /// <devdoc> 219 /// <para>[To be supplied.]</para> 220 /// </devdoc> 221 public bool KeepFiles { 222 get { return keepFiles; } 223 set { keepFiles = value; } 224 } 225 KeepFile(string fileName)226 bool KeepFile(string fileName) { 227 object keep = files[fileName]; 228 if (keep == null) return false; 229 return (bool)keep; 230 } 231 232 /// <devdoc> 233 /// <para>[To be supplied.]</para> 234 /// </devdoc> 235 [ResourceExposure(ResourceScope.None)] 236 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] Delete()237 public void Delete() { 238 if (files != null && files.Count > 0) { 239 string[] fileNames = new string[files.Count]; 240 files.Keys.CopyTo(fileNames, 0); 241 foreach (string fileName in fileNames) { 242 if (!KeepFile(fileName)) { 243 Delete(fileName); 244 files.Remove(fileName); 245 } 246 } 247 } 248 } 249 250 // This function deletes files after reverting impersonation. 251 [ResourceExposure(ResourceScope.None)] 252 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] SafeDelete()253 internal void SafeDelete() { 254 #if !FEATURE_PAL 255 WindowsImpersonationContext impersonation = Executor.RevertImpersonation(); 256 #endif 257 try{ 258 Delete(); 259 } 260 finally { 261 #if !FEATURE_PAL 262 Executor.ReImpersonate(impersonation); 263 #endif 264 } 265 } 266 267 [ResourceExposure(ResourceScope.Machine)] 268 [ResourceConsumption(ResourceScope.Machine)] Delete(string fileName)269 void Delete(string fileName) { 270 try { 271 File.Delete(fileName); 272 } 273 catch { 274 // Ignore all exceptions 275 } 276 } 277 278 [ResourceExposure(ResourceScope.Machine)] 279 [ResourceConsumption(ResourceScope.Machine)] GetTempFileName(string tempDir)280 static string GetTempFileName(string tempDir) { 281 string fileName; 282 if (String.IsNullOrEmpty(tempDir)) tempDir = Path.GetTempPath(); 283 284 string randomFileName = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); 285 286 if (tempDir.EndsWith("\\", StringComparison.Ordinal)) 287 fileName = tempDir + randomFileName; 288 else 289 fileName = tempDir + "\\" + randomFileName; 290 291 return fileName; 292 } 293 } 294 } 295