The Labs \ Source Viewer \ SSCLI \ System.CodeDom.Compiler \ Executor

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Executor.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.CodeDom.Compiler
  16. {
  17.    
  18.     using System.Diagnostics;
  19.     using System;
  20.     using System.ComponentModel;
  21.     using System.Text;
  22.     using System.Threading;
  23.     using System.IO;
  24.     using System.Collections;
  25.     using System.Collections.Specialized;
  26.     using System.Reflection;
  27.     using System.Runtime.InteropServices;
  28.     using System.CodeDom;
  29.     using System.Security;
  30.     using System.Security.Permissions;
  31.     using System.Security.Principal;
  32.     using Microsoft.Win32;
  33.     using Microsoft.Win32.SafeHandles;
  34.     using System.Globalization;
  35.     using System.Runtime.CompilerServices;
  36.     using System.Runtime.ConstrainedExecution;
  37.    
  38.     /// <devdoc>
  39.     /// <para>
  40.     /// Provides command execution functions for the CodeDom compiler.
  41.     /// </para>
  42.     /// </devdoc>
  43.     [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
  44.     [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
  45.     public sealed class Executor
  46.     {
  47.        
  48.         // How long (in milliseconds) do we wait for the program to terminate
  49.         private const int ProcessTimeOut = 600000;
  50.        
  51.         private Executor()
  52.         {
  53.         }
  54.        
  55.         /// <devdoc>
  56.         /// <para>
  57.         /// Gets the runtime install directory.
  58.         /// </para>
  59.         /// </devdoc>
  60.         static internal string GetRuntimeInstallDirectory()
  61.         {
  62.             return RuntimeEnvironment.GetRuntimeDirectory();
  63.         }
  64.        
  65.         private static FileStream CreateInheritedFile(string file)
  66.         {
  67.             return new FileStream(file, FileMode.CreateNew, FileAccess.Write, FileShare.Read | FileShare.Inheritable);
  68.         }
  69.        
  70.         /// <devdoc>
  71.         /// </devdoc>
  72.         public static void ExecWait(string cmd, TempFileCollection tempFiles)
  73.         {
  74.             string outputName = null;
  75.             string errorName = null;
  76.             ExecWaitWithCapture(null, cmd, tempFiles, ref outputName, ref errorName);
  77.         }
  78.        
  79.         /// <devdoc>
  80.         /// <para>[To be supplied.]</para>
  81.         /// </devdoc>
  82.         public static int ExecWaitWithCapture(string cmd, TempFileCollection tempFiles, ref string outputName, ref string errorName)
  83.         {
  84.             return ExecWaitWithCapture(null, cmd, Environment.CurrentDirectory, tempFiles, ref outputName, ref errorName, null);
  85.         }
  86.        
  87.         /// <devdoc>
  88.         /// <para>[To be supplied.]</para>
  89.         /// </devdoc>
  90.         public static int ExecWaitWithCapture(string cmd, string currentDir, TempFileCollection tempFiles, ref string outputName, ref string errorName)
  91.         {
  92.             return ExecWaitWithCapture(null, cmd, currentDir, tempFiles, ref outputName, ref errorName, null);
  93.         }
  94.        
  95.         /// <devdoc>
  96.         /// <para>[To be supplied.]</para>
  97.         /// </devdoc>
  98.         public static int ExecWaitWithCapture(IntPtr userToken, string cmd, TempFileCollection tempFiles, ref string outputName, ref string errorName)
  99.         {
  100.             return ExecWaitWithCapture(new SafeUserTokenHandle(userToken, false), cmd, Environment.CurrentDirectory, tempFiles, ref outputName, ref errorName, null);
  101.         }
  102.        
  103.         /// <devdoc>
  104.         /// <para>[To be supplied.]</para>
  105.         /// </devdoc>
  106.         public static int ExecWaitWithCapture(IntPtr userToken, string cmd, string currentDir, TempFileCollection tempFiles, ref string outputName, ref string errorName)
  107.         {
  108.             return ExecWaitWithCapture(new SafeUserTokenHandle(userToken, false), cmd, Environment.CurrentDirectory, tempFiles, ref outputName, ref errorName, null);
  109.         }
  110.        
  111.         /// <devdoc>
  112.         /// <para>[To be supplied.]</para>
  113.         /// </devdoc>
  114.         static internal int ExecWaitWithCapture(SafeUserTokenHandle userToken, string cmd, string currentDir, TempFileCollection tempFiles, ref string outputName, ref string errorName, string trueCmdLine)
  115.         {
  116.             int retValue = 0;
  117.             // Undo any current impersonation, call ExecWaitWithCaptureUnimpersonated, and reimpersonate
  118.            
  119.             // Execute the process
  120.             retValue = ExecWaitWithCaptureUnimpersonated(userToken, cmd, currentDir, tempFiles, ref outputName, ref errorName, trueCmdLine);
  121.             return retValue;
  122.         }
  123.        
  124.         unsafe private static int ExecWaitWithCaptureUnimpersonated(SafeUserTokenHandle userToken, string cmd, string currentDir, TempFileCollection tempFiles, ref string outputName, ref string errorName, string trueCmdLine)
  125.         {
  126.            
  127.             IntSecurity.UnmanagedCode.Demand();
  128.            
  129.             FileStream output;
  130.             FileStream error;
  131.            
  132.             int retValue = 0;
  133.            
  134.             if (outputName == null || outputName.Length == 0)
  135.                 outputName = tempFiles.AddExtension("out");
  136.            
  137.             if (errorName == null || errorName.Length == 0)
  138.                 errorName = tempFiles.AddExtension("err");
  139.            
  140.             // Create the files
  141.             output = CreateInheritedFile(outputName);
  142.             error = CreateInheritedFile(errorName);
  143.            
  144.             bool success = false;
  145.             SafeNativeMethods.PROCESS_INFORMATION pi = new SafeNativeMethods.PROCESS_INFORMATION();
  146.             SafeProcessHandle procSH = new SafeProcessHandle();
  147.             SafeThreadHandle threadSH = new SafeThreadHandle();
  148.             SafeUserTokenHandle primaryToken = null;
  149.            
  150.             try {
  151.                 // Output the command line...
  152.                 StreamWriter sw = new StreamWriter(output, Encoding.UTF8);
  153.                 sw.Write(currentDir);
  154.                 sw.Write("> ");
  155.                 // 'true' command line is used in case the command line points to
  156.                 // a response file
  157.                 sw.WriteLine(trueCmdLine != null ? trueCmdLine : cmd);
  158.                 sw.WriteLine();
  159.                 sw.WriteLine();
  160.                 sw.Flush();
  161.                
  162.                 NativeMethods.STARTUPINFO si = new NativeMethods.STARTUPINFO();
  163.                
  164.                 si.cb = Marshal.SizeOf(si);
  165.                 si.dwFlags = NativeMethods.STARTF_USESTDHANDLES;
  166.                 si.hStdOutput = output.SafeFileHandle;
  167.                 si.hStdError = error.SafeFileHandle;
  168.                 si.hStdInput = new SafeFileHandle(UnsafeNativeMethods.GetStdHandle(NativeMethods.STD_INPUT_HANDLE), false);
  169.                
  170.                 //
  171.                 // Prepare the environment
  172.                 //
  173.                 #if PLATFORM_UNIX
  174.                
  175.                 StringDictionary environment = new CaseSensitiveStringDictionary();
  176.                
  177.                 #else
  178.                
  179.                 StringDictionary environment = new StringDictionary();
  180.                
  181.                 #endif // PLATFORM_UNIX
  182.                
  183.                
  184.                
  185.                 // Add the current environment
  186.                
  187.                 foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables())
  188.                    
  189.                     environment.Add((string)entry.Key, (string)entry.Value);
  190.                
  191.                
  192.                
  193.                 // Add the flag to indicate restricted security in the process
  194.                 environment["_ClrRestrictSecAttributes"] = "1";
  195.                
  196.                 #if DEBUG
  197.                 environment["OANOCACHE"] = "1";
  198.                 #endif
  199.                
  200.                 // set up the environment block parameter
  201.                 byte[] environmentBytes = EnvironmentBlock.ToByteArray(environment, false);
  202.                 fixed (byte* environmentBytesPtr = environmentBytes) {
  203.                     IntPtr environmentPtr = new IntPtr((void*)environmentBytesPtr);
  204.                    
  205.                     if (userToken == null || userToken.IsInvalid) {
  206.                         RuntimeHelpers.PrepareConstrainedRegions();
  207.                         try {
  208.                         }
  209.                         finally {
  210.                             success = NativeMethods.CreateProcess(null, new StringBuilder(cmd), null, null, true, 0, environmentPtr, currentDir, si, pi
  211.                                 // String lpApplicationName,
  212.                                 // String lpCommandLine,
  213.                                 // SECURITY_ATTRIBUTES lpProcessAttributes,
  214.                                 // SECURITY_ATTRIBUTES lpThreadAttributes,
  215.                                 // bool bInheritHandles,
  216.                                 // int dwCreationFlags,
  217.                                 // int lpEnvironment,
  218.                                 // String lpCurrentDirectory,
  219.                                 // STARTUPINFO lpStartupInfo,
  220.                             );
  221.                             // PROCESS_INFORMATION lpProcessInformation);
  222.                             if (pi.hProcess != (IntPtr)0 && pi.hProcess != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE)
  223.                                 procSH.InitialSetHandle(pi.hProcess);
  224.                             if (pi.hThread != (IntPtr)0 && pi.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE)
  225.                                 threadSH.InitialSetHandle(pi.hThread);
  226.                         }
  227.                     }
  228.                     else {
  229.                         throw new NotSupportedException();
  230.                     }
  231.                 }
  232.             }
  233.             finally {
  234.                 // Close the file handles
  235.                 if (!success && (primaryToken != null && !primaryToken.IsInvalid)) {
  236.                     primaryToken.Close();
  237.                     primaryToken = null;
  238.                 }
  239.                
  240.                 output.Close();
  241.                 error.Close();
  242.             }
  243.            
  244.             if (success) {
  245.                
  246.                 try {
  247.                     int ret = NativeMethods.WaitForSingleObject(procSH, ProcessTimeOut);
  248.                    
  249.                     // Check for timeout
  250.                     if (ret == NativeMethods.WAIT_TIMEOUT) {
  251.                         throw new ExternalException(SR.GetString(SR.ExecTimeout, cmd), NativeMethods.WAIT_TIMEOUT);
  252.                     }
  253.                    
  254.                     if (ret != NativeMethods.WAIT_OBJECT_0) {
  255.                         throw new ExternalException(SR.GetString(SR.ExecBadreturn, cmd), Marshal.GetLastWin32Error());
  256.                     }
  257.                    
  258.                     // Check the process's exit code
  259.                     int status = NativeMethods.STILL_ACTIVE;
  260.                     if (!NativeMethods.GetExitCodeProcess(procSH, out status)) {
  261.                         throw new ExternalException(SR.GetString(SR.ExecCantGetRetCode, cmd), Marshal.GetLastWin32Error());
  262.                     }
  263.                    
  264.                     retValue = status;
  265.                 }
  266.                 finally {
  267.                     procSH.Close();
  268.                     threadSH.Close();
  269.                     if (primaryToken != null && !primaryToken.IsInvalid)
  270.                         primaryToken.Close();
  271.                 }
  272.             }
  273.             else {
  274.                 throw new ExternalException(SR.GetString(SR.ExecCantExec, cmd), Marshal.GetLastWin32Error());
  275.             }
  276.            
  277.             return retValue;
  278.         }
  279.        
  280.        
  281.        
  282.     }
  283.    
  284. }

Developer Fusion