File: FrameworkFork\Microsoft.CodeDom\Compiler\TempFiles.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
namespace Microsoft.CodeDom.Compiler
{
    using System;
    using System.Collections;
    using System.Diagnostics;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    using Microsoft.Win32;
    using System.Security;
 
 
    using System.ComponentModel;
 
    using System.Globalization;
    using System.Runtime.Versioning;
 
    /// <devdoc>
    ///    <para>Represents a collection of temporary file names that are all based on a
    ///       single base filename located in a temporary directory.</para>
    /// </devdoc>
 
 
    // [Serializable],
    public class TempFileCollection : ICollection, IDisposable
    {
        private string _basePath;
        private string _tempDir;
        private bool _keepFiles;
        private Hashtable _files;
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public TempFileCollection() : this(null, false)
        {
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public TempFileCollection(string tempDir) : this(tempDir, false)
        {
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public TempFileCollection(string tempDir, bool keepFiles)
        {
            _keepFiles = keepFiles;
            _tempDir = tempDir;
#if !FEATURE_CASE_SENSITIVE_FILESYSTEM            
            _files = new Hashtable(StringComparer.OrdinalIgnoreCase);
#else
            files = new Hashtable();
#endif
        }
 
        /// <internalonly/>
        /// <devdoc>
        /// <para> To allow it's stuff to be cleaned up</para>
        /// </devdoc>
        void IDisposable.Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            // It is safe to call Delete from here even if Dispose is called from Finalizer
            // because the graph of objects is guaranteed to be there and
            // neither Hashtable nor String have a finalizer of their own that could 
            // be called before TempFileCollection Finalizer
            Delete();
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        ~TempFileCollection()
        {
            Dispose(false);
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public string AddExtension(string fileExtension)
        {
            return AddExtension(fileExtension, _keepFiles);
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public string AddExtension(string fileExtension, bool keepFile)
        {
            if (fileExtension == null || fileExtension.Length == 0)
                throw new ArgumentException(string.Format(SRCodeDom.InvalidNullEmptyArgument, "fileExtension"), "fileExtension");  // fileExtension not specified
            string fileName = BasePath + "." + fileExtension;
            AddFile(fileName, keepFile);
            return fileName;
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public void AddFile(string fileName, bool keepFile)
        {
            if (fileName == null || fileName.Length == 0)
                throw new ArgumentException(string.Format(SRCodeDom.InvalidNullEmptyArgument, "fileName"), "fileName");  // fileName not specified
 
            if (_files[fileName] != null)
                throw new ArgumentException(string.Format(SRCodeDom.DuplicateFileName, fileName), "fileName");  // duplicate fileName
            _files.Add(fileName, (object)keepFile);
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public IEnumerator GetEnumerator()
        {
            return _files.Keys.GetEnumerator();
        }
 
        /// <internalonly/>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _files.Keys.GetEnumerator();
        }
 
        /// <internalonly/>
        void ICollection.CopyTo(Array array, int start)
        {
            _files.Keys.CopyTo(array, start);
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public void CopyTo(string[] fileNames, int start)
        {
            _files.Keys.CopyTo(fileNames, start);
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public int Count
        {
            get
            {
                return _files.Count;
            }
        }
 
        /// <internalonly/>
        int ICollection.Count
        {
            get { return _files.Count; }
        }
 
        /// <internalonly/>
        object ICollection.SyncRoot
        {
            get { return null; }
        }
 
        /// <internalonly/>
        bool ICollection.IsSynchronized
        {
            get { return false; }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public string TempDir
        {
            get { return _tempDir == null ? string.Empty : _tempDir; }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public string BasePath
        {
            get
            {
                EnsureTempNameCreated();
                return _basePath;
            }
        }
 
 
 
        private void EnsureTempNameCreated()
        {
            if (_basePath == null)
            {
                string tempFileName = null;
                FileStream tempFileStream;
                bool uniqueFile = false;
                int retryCount = 5000;
                do
                {
                    try
                    {
                        _basePath = GetTempFileName(TempDir);
 
                        string full = Path.GetFullPath(_basePath);
 
                        // make sure the filename is unique. 
                        tempFileName = _basePath + ".tmp";
                        using (tempFileStream = new FileStream(tempFileName, FileMode.CreateNew, FileAccess.Write)) { }
                        uniqueFile = true;
                    }
                    catch (IOException e)
                    {
                        retryCount--;
 
                        uint HR_ERROR_FILE_EXISTS = unchecked(((uint)0x80070000) | NativeMethods.ERROR_FILE_EXISTS);
                        if (retryCount == 0 || Marshal.GetHRForException(e) != HR_ERROR_FILE_EXISTS)
                            throw;
 
                        uniqueFile = false;
                    }
                } while (!uniqueFile);
                _files.Add(tempFileName, _keepFiles);
            }
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public bool KeepFiles
        {
            get { return _keepFiles; }
            set { _keepFiles = value; }
        }
 
        private bool KeepFile(string fileName)
        {
            object keep = _files[fileName];
            if (keep == null) return false;
            return (bool)keep;
        }
 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
 
 
        public void Delete()
        {
            if (_files != null && _files.Count > 0)
            {
                string[] fileNames = new string[_files.Count];
                _files.Keys.CopyTo(fileNames, 0);
                foreach (string fileName in fileNames)
                {
                    if (!KeepFile(fileName))
                    {
                        Delete(fileName);
                        _files.Remove(fileName);
                    }
                }
            }
        }
 
        // This function deletes files after reverting impersonation.
        internal void SafeDelete()
        {
            try
            {
                Delete();
            }
            finally
            {
            }
        }
 
        private void Delete(string fileName)
        {
            try
            {
                File.Delete(fileName);
            }
            catch
            {
                // Ignore all exceptions
            }
        }
 
 
 
        private static string GetTempFileName(string tempDir)
        {
            string fileName;
            if (String.IsNullOrEmpty(tempDir)) tempDir = Path.GetTempPath();
 
            string randomFileName = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
 
            if (tempDir.EndsWith("\\", StringComparison.Ordinal))
                fileName = tempDir + randomFileName;
            else
                fileName = tempDir + "\\" + randomFileName;
 
            return fileName;
        }
    }
}