Committed patch for 81732
[mono.git] / mcs / class / corlib / System / Environment.cs
1 //------------------------------------------------------------------------------
2 // 
3 // System.Environment.cs 
4 //
5 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
6 // 
7 // Author:         Jim Richardson, develop@wtfo-guru.com
8 //                 Dan Lewis (dihlewis@yahoo.co.uk)
9 // Created:        Saturday, August 11, 2001 
10 //
11 //------------------------------------------------------------------------------
12 //
13 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System.IO;
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Security;
39 using System.Security.Permissions;
40 using System.Text;
41
42 namespace System {
43
44 #if NET_2_0
45         public static class Environment {
46 #else
47         public sealed class Environment {
48
49                 private Environment ()
50                 {
51                 }
52 #endif
53                 /*
54                  * This is the version number of the corlib-runtime interface. When
55                  * making changes to this interface (by changing the layout
56                  * of classes the runtime knows about, changing icall signature or
57                  * semantics etc), increment this variable. Also increment the
58                  * pair of this variable in the runtime in metadata/appdomain.c.
59                  * Changes which are already detected at runtime, like the addition
60                  * of icalls, do not require an increment.
61                  */
62                 private const int mono_corlib_version = 58;
63                 
64                 public enum SpecialFolder
65                 {       // TODO: Determine if these windoze style folder identifiers 
66                         //       have unix/linux counterparts
67 #if NET_2_0
68                         MyDocuments = 0x05,
69 #endif
70 #if NET_1_1
71                         Desktop = 0x00,
72                         MyComputer = 0x11,
73 #endif
74                         Programs = 0x02,
75                         Personal = 0x05,
76                         Favorites = 0x06,
77                         Startup = 0x07,
78                         Recent = 0x08,
79                         SendTo = 0x09,
80                         StartMenu = 0x0b,
81                         MyMusic = 0x0d,
82                         DesktopDirectory = 0x10,
83                         Templates = 0x15,
84                         ApplicationData = 0x1a,
85                         LocalApplicationData = 0x1c,
86                         InternetCache = 0x20,
87                         Cookies = 0x21,
88                         History = 0x22,
89                         CommonApplicationData   = 0x23,
90                         System = 0x25,
91                         ProgramFiles = 0x26,
92                         MyPictures = 0x27,
93                         CommonProgramFiles = 0x2b,
94                 }
95
96                 /// <summary>
97                 /// Gets the command line for this process
98                 /// </summary>
99                 public static string CommandLine {
100                         // note: security demand inherited from calling GetCommandLineArgs
101                         get {
102                                 // FIXME: we may need to quote, but any sane person
103                                 // should use GetCommandLineArgs () instead.
104                                 return String.Join (" ", GetCommandLineArgs ());
105                         }
106                 }
107
108                 /// <summary>
109                 /// Gets or sets the current directory. Actually this is supposed to get
110                 /// and/or set the process start directory acording to the documentation
111                 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
112                 /// </summary>
113                 public static string CurrentDirectory
114                 {
115                         get {
116                                 return Directory.GetCurrentDirectory ();
117                         }
118                         set {
119                                 Directory.SetCurrentDirectory (value);
120                         }
121                 }
122
123                 /// <summary>
124                 /// Gets or sets the exit code of this process
125                 /// </summary>
126                 public extern static int ExitCode
127                 {       
128                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
129                         get;
130                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
131                         set;
132                 }
133
134 #if NET_1_1
135                 static
136 #endif
137                 public extern bool HasShutdownStarted
138                 {
139                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
140                         get;
141                 }
142                 
143
144                 /// <summary>
145                 /// Gets the name of the local computer
146                 /// </summary>
147                 public extern static string MachineName {
148                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
149                         [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
150                         [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
151                         get;
152                 }
153
154                 /// <summary>
155                 /// Gets the standard new line value
156                 /// </summary>
157                 public extern static string NewLine {
158                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
159                         get;
160                 }
161
162                 //
163                 // Support methods and fields for OSVersion property
164                 //
165                 static OperatingSystem os;
166
167                 internal static extern PlatformID Platform {
168                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
169                         get;
170                 }
171
172                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
173                 internal static extern string GetOSVersionString ();
174
175                 /// <summary>
176                 /// Gets the current OS version information
177                 /// </summary>
178                 public static OperatingSystem OSVersion {
179                         get {
180                                 if (os == null) {
181                                         Version v = Version.CreateFromString (GetOSVersionString ());
182                                         PlatformID p = Platform;
183 #if NET_2_0
184                                         if ((int) p == 128)
185                                                 p = PlatformID.Unix;
186 #endif
187                                         os = new OperatingSystem (p, v);
188                                 }
189                                 return os;
190                         }
191                 }
192
193                 /// <summary>
194                 /// Get StackTrace
195                 /// </summary>
196                 public static string StackTrace {
197                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
198                         get {
199                                 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
200                                 return trace.ToString ();
201                         }
202                 }
203
204                 /// <summary>
205                 /// Get a fully qualified path to the system directory
206                 /// </summary>
207                 public static string SystemDirectory {
208                         get {
209                                 return GetFolderPath (SpecialFolder.System);
210                         }
211                 }
212
213                 /// <summary>
214                 /// Get the number of milliseconds that have elapsed since the system was booted
215                 /// </summary>
216                 public extern static int TickCount {
217                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
218                         get;
219                 }
220
221                 /// <summary>
222                 /// Get UserDomainName
223                 /// </summary>
224                 public static string UserDomainName {
225                         // FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
226                         [EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
227                         get {
228                                 return MachineName;
229                         }
230                 }
231
232                 /// <summary>
233                 /// Gets a flag indicating whether the process is in interactive mode
234                 /// </summary>
235                 [MonoTODO ("Currently always returns false, regardless of interactive state")]
236                 public static bool UserInteractive {
237                         get {
238                                 return false;
239                         }
240                 }
241
242                 /// <summary>
243                 /// Get the user name of current process is running under
244                 /// </summary>
245                 public extern static string UserName {
246                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
247                         [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
248                         get;
249                 }
250
251                 /// <summary>
252                 /// Get the version of the common language runtime 
253                 /// </summary>
254                 public static Version Version {
255                         get {
256                                 return new Version (Consts.FxFileVersion);
257                         }
258                 }
259
260                 /// <summary>
261                 /// Get the amount of physical memory mapped to process
262                 /// </summary>
263                 [MonoTODO ("Currently always returns zero")]
264                 public static long WorkingSet {
265                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
266                         get { return 0; }
267                 }
268
269                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
270                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
271                 public extern static void Exit (int exitCode);
272
273                 /// <summary>
274                 /// Substitute environment variables in the argument "name"
275                 /// </summary>
276                 public static string ExpandEnvironmentVariables (string name)
277                 {
278                         if (name == null)
279                                 throw new ArgumentNullException ("name");
280
281                         int off1 = name.IndexOf ('%');
282                         if (off1 == -1)
283                                 return name;
284
285                         int len = name.Length;
286                         int off2 = 0;
287                         if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
288                                 return name;
289
290                         StringBuilder result = new StringBuilder ();
291                         result.Append (name, 0, off1);
292                         Hashtable tbl = null;
293                         do {
294                                 string var = name.Substring (off1 + 1, off2 - off1 - 1);
295                                 string value = GetEnvironmentVariable (var);
296                                 if (value == null && Environment.IsRunningOnWindows) {
297                                         // On windows, env. vars. are case insensitive
298                                         if (tbl == null)
299                                                 tbl = GetEnvironmentVariablesNoCase ();
300
301                                         value = tbl [var] as string;
302                                 }
303                                 
304                                 // If value not found, add %FOO to stream,
305                                 //  and use the closing % for the next iteration.
306                                 // If value found, expand it in place of %FOO%
307                                 if (value == null) {
308                                         result.Append ('%');
309                                         result.Append (var);
310                                         off2--;
311                                 } else {
312                                         result.Append (value);
313                                 }
314                                 int oldOff2 = off2;
315                                 off1 = name.IndexOf ('%', off2 + 1);
316                                 // If no % found for off1, don't look for one for off2
317                                 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
318                                 // textLen is the length of text between the closing % of current iteration
319                                 //  and the starting % of the next iteration if any. This text is added to output
320                                 int textLen;
321                                 // If no new % found, use all the remaining text
322                                 if (off1 == -1 || off2 == -1)
323                                         textLen = len - oldOff2 - 1;
324                                 // If value found in current iteration, use text after current closing % and next %
325                                 else if(value != null)
326                                         textLen = off1 - oldOff2 - 1;
327                                 // If value not found in current iteration, but a % was found for next iteration,
328                                 //  use text from current closing % to the next %.
329                                 else
330                                         textLen = off1 - oldOff2;
331                                 if(off1 >= oldOff2 || off1 == -1)
332                                         result.Append (name, oldOff2+1, textLen);
333                         } while (off2 > -1 && off2 < len);
334                                 
335                         return result.ToString ();
336
337                 }
338
339                 /// <summary>
340                 /// Return an array of the command line arguments of the current process
341                 /// </summary>
342                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
343                 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
344                 public extern static string[] GetCommandLineArgs ();
345
346                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
347                 internal extern static string internalGetEnvironmentVariable (string name);
348
349                 /// <summary>
350                 /// Return a string containing the value of the environment
351                 /// variable identifed by parameter "variable"
352                 /// </summary>
353                 public static string GetEnvironmentVariable (string name)
354                 {
355                         if (SecurityManager.SecurityEnabled) {
356                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, name).Demand ();
357                         }
358                         return internalGetEnvironmentVariable (name);
359                 }
360
361                 static Hashtable GetEnvironmentVariablesNoCase ()
362                 {
363                         Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
364                                                         CaseInsensitiveComparer.Default);
365
366                         foreach (string name in GetEnvironmentVariableNames ()) {
367                                 vars [name] = internalGetEnvironmentVariable (name);
368                         }
369
370                         return vars;
371                 }
372
373                 /// <summary>
374                 /// Return a set of all environment variables and their values
375                 /// </summary>
376 #if NET_2_0
377                 public static IDictionary GetEnvironmentVariables ()
378                 {
379                         StringBuilder sb = null;
380                         if (SecurityManager.SecurityEnabled) {
381                                 // we must have access to each variable to get the lot
382                                 sb = new StringBuilder ();
383                                 // but (performance-wise) we do not want a stack-walk
384                                 // for each of them so we concatenate them
385                         }
386
387                         Hashtable vars = new Hashtable ();
388                         foreach (string name in GetEnvironmentVariableNames ()) {
389                                 vars [name] = internalGetEnvironmentVariable (name);
390                                 if (sb != null) {
391                                         sb.Append (name);
392                                         sb.Append (";");
393                                 }
394                         }
395
396                         if (sb != null) {
397                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
398                         }
399                         return vars;
400                 }
401 #else
402                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
403                 public static IDictionary GetEnvironmentVariables ()
404                 {
405                         Hashtable vars = new Hashtable ();
406                         foreach (string name in GetEnvironmentVariableNames ()) {
407                                 vars [name] = internalGetEnvironmentVariable (name);
408                         }
409                         return vars;
410                 }
411 #endif
412
413                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
414                 private extern static string GetWindowsFolderPath (int folder);
415
416                 /// <summary>
417                 /// Returns the fully qualified path of the
418                 /// folder specified by the "folder" parameter
419                 /// </summary>
420                 public static string GetFolderPath (SpecialFolder folder)
421                 {
422                         string dir = null;
423
424                         if (Environment.IsRunningOnWindows) {
425                                 dir = GetWindowsFolderPath ((int) folder);
426                         } else {
427                                 dir = InternalGetFolderPath (folder);
428                         }
429
430                         if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
431                                 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
432                         }
433                         return dir;
434                 }
435
436                 private static string ReadXdgUserDir (string config_dir, string home_dir, 
437                         string key, string fallback)
438                 {
439                         string env_path = internalGetEnvironmentVariable (key);
440                         if (env_path != null && env_path != String.Empty) {
441                                 return env_path;
442                         }
443
444                         string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
445
446                         if (!File.Exists (user_dirs_path)) {
447                                 return Path.Combine (home_dir, fallback);
448                         }
449
450                         try {
451                                 using(StreamReader reader = new StreamReader (user_dirs_path)) {
452                                         string line;
453                                         while ((line = reader.ReadLine ()) != null) {
454                                                 line = line.Trim ();
455                                                 int delim_index = line.IndexOf ('=');
456                                                 if (delim_index > 8 && line.Substring (0, delim_index) == key) {
457                                                         return Path.Combine (home_dir, line.Substring (delim_index + 1));
458                                                 }
459                                         }
460                                 }
461                         } catch (FileNotFoundException) {
462                         }
463
464                         return Path.Combine (home_dir, fallback);
465                 }
466
467
468                 // the security runtime (and maybe other parts of corlib) needs the
469                 // information to initialize themselves before permissions can be checked
470                 internal static string InternalGetFolderPath (SpecialFolder folder)
471                 {
472                         string home = internalGetHome ();
473
474                         // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
475
476                         // note: skip security check for environment variables
477                         string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
478                         if ((data == null) || (data == String.Empty)) {
479                                 data = Path.Combine (home, ".local");
480                                 data = Path.Combine (data, "share");
481                         }
482
483                         // note: skip security check for environment variables
484                         string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
485                         if ((config == null) || (config == String.Empty)) {
486                                 config = Path.Combine (home, ".config");
487                         }
488
489                         switch (folder) {
490 #if NET_1_1
491                         // MyComputer is a virtual directory
492                         case SpecialFolder.MyComputer:
493                                 return String.Empty;
494 #endif
495                         // personal == ~
496                         case SpecialFolder.Personal:
497                                 return home;
498                         // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
499                         case SpecialFolder.ApplicationData:
500                                 return config;
501                         //use FDO's DATA_HOME. This is *NOT* synced
502                         case SpecialFolder.LocalApplicationData:
503                                 return data;
504 #if NET_1_1
505                         case SpecialFolder.Desktop:
506 #endif
507                         case SpecialFolder.DesktopDirectory:
508                                 return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
509
510                         case SpecialFolder.MyMusic:
511                                 return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
512
513                         case SpecialFolder.MyPictures:
514                                 return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
515                                 
516                         // these simply dont exist on Linux
517                         // The spec says if a folder doesnt exist, we
518                         // should return ""
519                         case SpecialFolder.Favorites:
520                         case SpecialFolder.Programs:
521                         case SpecialFolder.SendTo:
522                         case SpecialFolder.StartMenu:
523                         case SpecialFolder.Startup:
524                         case SpecialFolder.Templates:
525                         case SpecialFolder.Cookies:
526                         case SpecialFolder.History:
527                         case SpecialFolder.InternetCache:
528                         case SpecialFolder.Recent:
529                         case SpecialFolder.CommonProgramFiles:
530                         case SpecialFolder.ProgramFiles:
531                         case SpecialFolder.System:
532                                 return String.Empty;
533                         // This is where data common to all users goes
534                         case SpecialFolder.CommonApplicationData:
535                                 return "/usr/share";
536                         default:
537                                 throw new ArgumentException ("Invalid SpecialFolder");
538                         }
539                 }
540
541                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
542                 public static string[] GetLogicalDrives ()
543                 {
544                         return GetLogicalDrivesInternal ();
545                 }
546
547                 // FIXME: Anyone using this anywhere ?
548                 static internal string GetResourceString (string s) { return String.Empty; }
549
550                 
551 #if NET_2_0
552                 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
553                 {
554                         switch (target) {
555                         case EnvironmentVariableTarget.Process:
556                                 return GetEnvironmentVariable (variable);
557                         case EnvironmentVariableTarget.Machine:
558                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
559                                 if (!IsRunningOnWindows)
560                                         return null;
561                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
562                                         return env.GetValue (variable).ToString ();
563                                 }
564                         case EnvironmentVariableTarget.User:
565                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
566                                 if (!IsRunningOnWindows)
567                                         return null;
568                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
569                                         return env.GetValue (variable).ToString ();
570                                 }
571                         default:
572                                 throw new ArgumentException ("target");
573                         }
574                 }
575
576                 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
577                 {
578                         IDictionary variables = (IDictionary)new Hashtable ();
579                         switch (target) {
580                         case EnvironmentVariableTarget.Process:
581                                 variables = GetEnvironmentVariables ();
582                                 break;
583                         case EnvironmentVariableTarget.Machine:
584                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
585                                 if (IsRunningOnWindows) {
586                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
587                                                 string[] value_names = env.GetValueNames ();
588                                                 foreach (string value_name in value_names)
589                                                         variables.Add (value_name, env.GetValue (value_name));
590                                         }
591                                 }
592                                 break;
593                         case EnvironmentVariableTarget.User:
594                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
595                                 if (IsRunningOnWindows) {
596                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
597                                                 string[] value_names = env.GetValueNames ();
598                                                 foreach (string value_name in value_names)
599                                                         variables.Add (value_name, env.GetValue (value_name));
600                                         }
601                                 }
602                                 break;
603                         default:
604                                 throw new ArgumentException ("target");
605                         }
606                         return variables;
607                 }
608
609                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
610                 public static void SetEnvironmentVariable (string variable, string value)
611                 {
612                         SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
613                 }
614
615                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
616                 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
617                 {
618                         if (variable == null)
619                                 throw new ArgumentNullException ("variable");
620                         if (variable == String.Empty)
621                                 throw new ArgumentException ("String cannot be of zero length.", "variable");
622                         if (variable.IndexOf ('=') != -1)
623                                 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
624                         if (variable[0] == '\0')
625                                 throw new ArgumentException ("The first char in the string is the null character.", "variable");
626
627                         switch (target) {
628                         case EnvironmentVariableTarget.Process:
629                                 InternalSetEnvironmentVariable (variable, value);
630                                 break;
631                         case EnvironmentVariableTarget.Machine:
632                                 if (!IsRunningOnWindows)
633                                         return;
634                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
635                                         if (value == null || value.Length == 0)
636                                                 env.DeleteValue (variable, false);
637                                         else
638                                                 env.SetValue (variable, value);
639                                 }
640                                 break;
641                         case EnvironmentVariableTarget.User:
642                                 if (!IsRunningOnWindows)
643                                         return;
644                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
645                                         if (value == null || value.Length == 0)
646                                                 env.DeleteValue (variable, false);
647                                         else
648                                                 env.SetValue (variable, value);
649                                 }
650                                 break;
651                         default:
652                                 throw new ArgumentException ("target");
653                         }
654                 }
655
656                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
657                 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
658
659                 public static extern int ProcessorCount {
660                         [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
661                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
662                         get;                    
663                 }
664
665                 [MonoTODO ("Not implemented")]
666                 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
667                 public static void FailFast (string message)
668                 {
669                         throw new NotImplementedException ();
670                 }
671 #endif
672
673                 // private methods
674
675                 internal static bool IsRunningOnWindows {
676                         get { return ((int) Platform != 128); }
677                 }
678
679                 private static string GacPath {
680                         get {
681                                 if (Environment.IsRunningOnWindows) {
682                                         /* On windows, we don't know the path where mscorlib.dll will be installed */
683                                         string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
684                                         return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
685                                 }
686
687                                 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
688                         }
689                 }
690
691                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
692                 private extern static string [] GetLogicalDrivesInternal ();
693
694                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
695                 private extern static string [] GetEnvironmentVariableNames ();
696
697                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
698                 internal extern static string GetMachineConfigPath ();
699
700                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
701                 internal extern static string internalGetGacPath ();
702
703                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
704                 internal extern static string internalGetHome ();
705         }
706 }
707