[bcl] Remove NET_4_0 defines from class libs.
[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 using System.Runtime.InteropServices;
42 using System.Threading;
43
44 namespace System {
45
46         [ComVisible (true)]
47         public static partial class Environment {
48
49                 /*
50                  * This is the version number of the corlib-runtime interface. When
51                  * making changes to this interface (by changing the layout
52                  * of classes the runtime knows about, changing icall signature or
53                  * semantics etc), increment this variable. Also increment the
54                  * pair of this variable in the runtime in metadata/appdomain.c.
55                  * Changes which are already detected at runtime, like the addition
56                  * of icalls, do not require an increment.
57                  */
58 #pragma warning disable 169
59                 private const int mono_corlib_version = 113;
60 #pragma warning restore 169
61
62                 [ComVisible (true)]
63                 public enum SpecialFolder
64                 {       
65                         MyDocuments = 0x05,
66                         Desktop = 0x00,
67                         MyComputer = 0x11,
68                         Programs = 0x02,
69                         Personal = 0x05,
70                         Favorites = 0x06,
71                         Startup = 0x07,
72                         Recent = 0x08,
73                         SendTo = 0x09,
74                         StartMenu = 0x0b,
75                         MyMusic = 0x0d,
76                         DesktopDirectory = 0x10,
77                         Templates = 0x15,
78                         ApplicationData = 0x1a,
79                         LocalApplicationData = 0x1c,
80                         InternetCache = 0x20,
81                         Cookies = 0x21,
82                         History = 0x22,
83                         CommonApplicationData   = 0x23,
84                         System = 0x25,
85                         ProgramFiles = 0x26,
86                         MyPictures = 0x27,
87                         CommonProgramFiles = 0x2b,
88                         MyVideos = 0x0e,
89                         NetworkShortcuts = 0x13,
90                         Fonts = 0x14,
91                         CommonStartMenu = 0x16,
92                         CommonPrograms = 0x17,
93                         CommonStartup = 0x18,
94                         CommonDesktopDirectory = 0x19,
95                         PrinterShortcuts = 0x1b,
96                         Windows = 0x24,
97                         UserProfile = 0x28,
98                         SystemX86 = 0x29,
99                         ProgramFilesX86 = 0x2a,
100                         CommonProgramFilesX86 = 0x2c,
101                         CommonTemplates = 0x2d,
102                         CommonDocuments = 0x2e,
103                         CommonAdminTools = 0x2f,
104                         AdminTools = 0x30,
105                         CommonMusic = 0x35,
106                         CommonPictures = 0x36,
107                         CommonVideos = 0x37,
108                         Resources = 0x38,
109                         LocalizedResources = 0x39,
110                         CommonOemLinks = 0x3a,
111                         CDBurning = 0x3b,
112                 }
113
114                 public
115                 enum SpecialFolderOption {
116                         None = 0,
117                         DoNotVerify = 0x4000,
118                         Create = 0x8000
119                 }
120
121                 /// <summary>
122                 /// Gets the command line for this process
123                 /// </summary>
124                 public static string CommandLine {
125                         // note: security demand inherited from calling GetCommandLineArgs
126                         get {
127                                 StringBuilder sb = new StringBuilder ();
128                                 foreach (string str in GetCommandLineArgs ()) {
129                                         bool escape = false;
130                                         string quote = "";
131                                         string s = str;
132                                         for (int i = 0; i < s.Length; i++) {
133                                                 if (quote.Length == 0 && Char.IsWhiteSpace (s [i])) {
134                                                         quote = "\"";
135                                                 } else if (s [i] == '"') {
136                                                         escape = true;
137                                                 }
138                                         }
139                                         if (escape && quote.Length != 0) {
140                                                 s = s.Replace ("\"", "\\\"");
141                                         }
142                                         sb.AppendFormat ("{0}{1}{0} ", quote, s);
143                                 }
144                                 if (sb.Length > 0)
145                                         sb.Length--;
146                                 return sb.ToString ();
147                         }
148                 }
149
150                 /// <summary>
151                 /// Gets or sets the current directory. Actually this is supposed to get
152                 /// and/or set the process start directory acording to the documentation
153                 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
154                 /// </summary>
155                 public static string CurrentDirectory
156                 {
157                         get {
158                                 return Directory.GetCurrentDirectory ();
159                         }
160                         set {
161                                 Directory.SetCurrentDirectory (value);
162                         }
163                 }
164                 
165 #if NET_4_5
166                 public static int CurrentManagedThreadId {
167                         get {
168                                 return Thread.CurrentThread.ManagedThreadId;
169                         }
170                 }
171 #endif
172
173                 /// <summary>
174                 /// Gets or sets the exit code of this process
175                 /// </summary>
176                 public extern static int ExitCode
177                 {       
178                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
179                         get;
180                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
181                         set;
182                 }
183
184                 static public extern bool HasShutdownStarted
185                 {
186                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
187                         get;
188                 }
189                 
190
191                 /// <summary>
192                 /// Gets the name of the local computer
193                 /// </summary>
194                 public extern static string MachineName {
195                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
196                         [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
197                         [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
198                         get;
199                 }
200
201                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
202                 extern static string GetNewLine ();
203
204                 static string nl;
205                 /// <summary>
206                 /// Gets the standard new line value
207                 /// </summary>
208                 public static string NewLine {
209                         get {
210                                 if (nl != null)
211                                         return nl;
212
213                                 nl = GetNewLine ();
214                                 return nl;
215                         }
216                 }
217
218                 //
219                 // Support methods and fields for OSVersion property
220                 //
221                 static OperatingSystem os;
222
223                 static extern PlatformID Platform {
224                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
225                         get;
226                 }
227
228                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
229                 internal static extern string GetOSVersionString ();
230
231                 /// <summary>
232                 /// Gets the current OS version information
233                 /// </summary>
234                 public static OperatingSystem OSVersion {
235                         get {
236                                 if (os == null) {
237                                         Version v = Version.CreateFromString (GetOSVersionString ());
238                                         PlatformID p = Platform;
239                                         if (p == PlatformID.MacOSX)
240                                                 p = PlatformID.Unix;
241                                         os = new OperatingSystem (p, v);
242                                 }
243                                 return os;
244                         }
245                 }
246
247                 /// <summary>
248                 /// Get StackTrace
249                 /// </summary>
250                 public static string StackTrace {
251                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
252                         get {
253                                 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
254                                 return trace.ToString ();
255                         }
256                 }
257 #if !NET_2_1
258                 /// <summary>
259                 /// Get a fully qualified path to the system directory
260                 /// </summary>
261                 public static string SystemDirectory {
262                         get {
263                                 return GetFolderPath (SpecialFolder.System);
264                         }
265                 }
266 #endif
267                 /// <summary>
268                 /// Get the number of milliseconds that have elapsed since the system was booted
269                 /// </summary>
270                 public extern static int TickCount {
271                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
272                         get;
273                 }
274
275                 /// <summary>
276                 /// Get UserDomainName
277                 /// </summary>
278                 public static string UserDomainName {
279                         // FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
280                         [EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
281                         get {
282                                 return MachineName;
283                         }
284                 }
285
286                 /// <summary>
287                 /// Gets a flag indicating whether the process is in interactive mode
288                 /// </summary>
289                 [MonoTODO ("Currently always returns false, regardless of interactive state")]
290                 public static bool UserInteractive {
291                         get {
292                                 return false;
293                         }
294                 }
295
296                 /// <summary>
297                 /// Get the user name of current process is running under
298                 /// </summary>
299                 public extern static string UserName {
300                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
301                         [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
302                         get;
303                 }
304
305                 /// <summary>
306                 /// Get the version of the common language runtime 
307                 /// </summary>
308                 public static Version Version {
309                         get {
310                                 return new Version (Consts.FxFileVersion);
311                         }
312                 }
313
314                 /// <summary>
315                 /// Get the amount of physical memory mapped to process
316                 /// </summary>
317                 [MonoTODO ("Currently always returns zero")]
318                 public static long WorkingSet {
319                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
320                         get { return 0; }
321                 }
322
323                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
324                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
325                 public extern static void Exit (int exitCode);
326
327                 /// <summary>
328                 /// Substitute environment variables in the argument "name"
329                 /// </summary>
330                 public static string ExpandEnvironmentVariables (string name)
331                 {
332                         if (name == null)
333                                 throw new ArgumentNullException ("name");
334
335                         int off1 = name.IndexOf ('%');
336                         if (off1 == -1)
337                                 return name;
338
339                         int len = name.Length;
340                         int off2 = 0;
341                         if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
342                                 return name;
343
344                         StringBuilder result = new StringBuilder ();
345                         result.Append (name, 0, off1);
346                         Hashtable tbl = null;
347                         do {
348                                 string var = name.Substring (off1 + 1, off2 - off1 - 1);
349                                 string value = GetEnvironmentVariable (var);
350                                 if (value == null && Environment.IsRunningOnWindows) {
351                                         // On windows, env. vars. are case insensitive
352                                         if (tbl == null)
353                                                 tbl = GetEnvironmentVariablesNoCase ();
354
355                                         value = tbl [var] as string;
356                                 }
357                                 
358                                 // If value not found, add %FOO to stream,
359                                 //  and use the closing % for the next iteration.
360                                 // If value found, expand it in place of %FOO%
361                                 int realOldOff2 = off2;
362                                 if (value == null) {
363                                         result.Append ('%');
364                                         result.Append (var);
365                                         off2--;
366                                 } else {
367                                         result.Append (value);
368                                 }
369                                 int oldOff2 = off2;
370                                 off1 = name.IndexOf ('%', off2 + 1);
371                                 // If no % found for off1, don't look for one for off2
372                                 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
373                                 // textLen is the length of text between the closing % of current iteration
374                                 //  and the starting % of the next iteration if any. This text is added to output
375                                 int textLen;
376                                 // If no new % found, use all the remaining text
377                                 if (off1 == -1 || off2 == -1)
378                                         textLen = len - oldOff2 - 1;
379                                 // If value found in current iteration, use text after current closing % and next %
380                                 else if(value != null)
381                                         textLen = off1 - oldOff2 - 1;
382                                 // If value not found in current iteration, but a % was found for next iteration,
383                                 //  use text from current closing % to the next %.
384                                 else
385                                         textLen = off1 - realOldOff2;
386                                 if(off1 >= oldOff2 || off1 == -1)
387                                         result.Append (name, oldOff2+1, textLen);
388                         } while (off2 > -1 && off2 < len);
389                                 
390                         return result.ToString ();
391
392                 }
393
394                 /// <summary>
395                 /// Return an array of the command line arguments of the current process
396                 /// </summary>
397                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
398                 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
399                 public extern static string[] GetCommandLineArgs ();
400
401                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
402                 internal extern static string internalGetEnvironmentVariable (string variable);
403
404                 /// <summary>
405                 /// Return a string containing the value of the environment
406                 /// variable identifed by parameter "variable"
407                 /// </summary>
408                 public static string GetEnvironmentVariable (string variable)
409                 {
410 #if !NET_2_1
411                         if (SecurityManager.SecurityEnabled) {
412                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, variable).Demand ();
413                         }
414 #endif
415                         return internalGetEnvironmentVariable (variable);
416                 }
417
418                 static Hashtable GetEnvironmentVariablesNoCase ()
419                 {
420                         Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
421                                                         CaseInsensitiveComparer.Default);
422
423                         foreach (string name in GetEnvironmentVariableNames ()) {
424                                 vars [name] = internalGetEnvironmentVariable (name);
425                         }
426
427                         return vars;
428                 }
429
430                 /// <summary>
431                 /// Return a set of all environment variables and their values
432                 /// </summary>
433 #if !NET_2_1
434                 public static IDictionary GetEnvironmentVariables ()
435                 {
436                         StringBuilder sb = null;
437                         if (SecurityManager.SecurityEnabled) {
438                                 // we must have access to each variable to get the lot
439                                 sb = new StringBuilder ();
440                                 // but (performance-wise) we do not want a stack-walk
441                                 // for each of them so we concatenate them
442                         }
443
444                         Hashtable vars = new Hashtable ();
445                         foreach (string name in GetEnvironmentVariableNames ()) {
446                                 vars [name] = internalGetEnvironmentVariable (name);
447                                 if (sb != null) {
448                                         sb.Append (name);
449                                         sb.Append (";");
450                                 }
451                         }
452
453                         if (sb != null) {
454                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
455                         }
456                         return vars;
457                 }
458 #else
459                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
460                 public static IDictionary GetEnvironmentVariables ()
461                 {
462                         Hashtable vars = new Hashtable ();
463                         foreach (string name in GetEnvironmentVariableNames ()) {
464                                 vars [name] = internalGetEnvironmentVariable (name);
465                         }
466                         return vars;
467                 }
468 #endif
469
470                 /// <summary>
471                 /// Returns the fully qualified path of the
472                 /// folder specified by the "folder" parameter
473                 /// </summary>
474                 public static string GetFolderPath (SpecialFolder folder)
475                 {
476                         return GetFolderPath (folder, SpecialFolderOption.None);
477                 }
478
479 // for monotouch, not monotouch_runtime
480 #if !(MONOTOUCH && FULL_AOT_RUNTIME)
481                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
482                 private extern static string GetWindowsFolderPath (int folder);
483
484                 public
485                 static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
486                 {
487                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
488
489                         string dir = null;
490
491                         if (Environment.IsRunningOnWindows)
492                                 dir = GetWindowsFolderPath ((int) folder);
493                         else
494                                 dir = UnixGetFolderPath (folder, option);
495
496 #if !NET_2_1
497                         if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
498                                 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
499                         }
500 #endif
501                         return dir;
502                 }
503
504                 private static string ReadXdgUserDir (string config_dir, string home_dir, string key, string fallback)
505                 {
506                         string env_path = internalGetEnvironmentVariable (key);
507                         if (env_path != null && env_path != String.Empty) {
508                                 return env_path;
509                         }
510
511                         string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
512
513                         if (!File.Exists (user_dirs_path)) {
514                                 return Path.Combine (home_dir, fallback);
515                         }
516
517                         try {
518                                 using(StreamReader reader = new StreamReader (user_dirs_path)) {
519                                         string line;
520                                         while ((line = reader.ReadLine ()) != null) {
521                                                 line = line.Trim ();
522                                                 int delim_index = line.IndexOf ('=');
523                                                 if(delim_index > 8 && line.Substring (0, delim_index) == key) {
524                                                         string path = line.Substring (delim_index + 1).Trim ('"');
525                                                         bool relative = false;
526                                                         
527                                                         if (path.StartsWithOrdinalUnchecked ("$HOME/")) {
528                                                                 relative = true;
529                                                                 path = path.Substring (6);
530                                                         } else if (!path.StartsWithOrdinalUnchecked ("/")) {
531                                                                 relative = true;
532                                                         }
533                                                         
534                                                         return relative ? Path.Combine (home_dir, path) : path;
535                                                 }
536                                         }
537                                 }
538                         } catch (FileNotFoundException) {
539                         }
540
541                         return Path.Combine (home_dir, fallback);
542                 }
543
544
545                 // the security runtime (and maybe other parts of corlib) needs the
546                 // information to initialize themselves before permissions can be checked
547                 internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
548                 {
549                         string home = internalGetHome ();
550
551                         // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
552
553                         // note: skip security check for environment variables
554                         string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
555                         if ((data == null) || (data == String.Empty)) {
556                                 data = Path.Combine (home, ".local");
557                                 data = Path.Combine (data, "share");
558                         }
559
560                         // note: skip security check for environment variables
561                         string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
562                         if ((config == null) || (config == String.Empty)) {
563                                 config = Path.Combine (home, ".config");
564                         }
565
566                         switch (folder) {
567                         // MyComputer is a virtual directory
568                         case SpecialFolder.MyComputer:
569                                 return String.Empty;
570
571                         // personal == ~
572                         case SpecialFolder.Personal:
573                                 return home;
574
575                         // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
576                         case SpecialFolder.ApplicationData:
577                                 return config;
578
579                         //use FDO's DATA_HOME. This is *NOT* synced
580                         case SpecialFolder.LocalApplicationData:
581                                 return data;
582
583                         case SpecialFolder.Desktop:
584                         case SpecialFolder.DesktopDirectory:
585                                 return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
586
587                         case SpecialFolder.MyMusic:
588                                 if (Platform == PlatformID.MacOSX)
589                                         return Path.Combine (home, "Music");
590                                 else
591                                         return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
592
593                         case SpecialFolder.MyPictures:
594                                 if (Platform == PlatformID.MacOSX)
595                                         return Path.Combine (home, "Pictures");
596                                 else
597                                         return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
598                         
599                         case SpecialFolder.Templates:
600                                 return ReadXdgUserDir (config, home, "XDG_TEMPLATES_DIR", "Templates");
601                         case SpecialFolder.MyVideos:
602                                 return ReadXdgUserDir (config, home, "XDG_VIDEOS_DIR", "Videos");
603                         case SpecialFolder.CommonTemplates:
604                                 return "/usr/share/templates";
605                         case SpecialFolder.Fonts:
606                                 if (Platform == PlatformID.MacOSX)
607                                         return Path.Combine (home, "Library", "Fonts");
608                                 
609                                 return Path.Combine (home, ".fonts");
610                         // these simply dont exist on Linux
611                         // The spec says if a folder doesnt exist, we
612                         // should return ""
613                         case SpecialFolder.Favorites:
614                                 if (Platform == PlatformID.MacOSX)
615                                         return Path.Combine (home, "Library", "Favorites");
616                                 else
617                                         return String.Empty;
618                                 
619                         case SpecialFolder.ProgramFiles:
620                                 if (Platform == PlatformID.MacOSX)
621                                         return "/Applications";
622                                 else
623                                         return String.Empty;
624
625                         case SpecialFolder.InternetCache:
626                                 if (Platform == PlatformID.MacOSX)
627                                         return Path.Combine (home, "Library", "Caches");
628                                 else
629                                         return String.Empty;
630
631                                 // #2873
632                         case SpecialFolder.UserProfile:
633                                 return home;
634
635                         case SpecialFolder.Programs:
636                         case SpecialFolder.SendTo:
637                         case SpecialFolder.StartMenu:
638                         case SpecialFolder.Startup:
639                         case SpecialFolder.Cookies:
640                         case SpecialFolder.History:
641                         case SpecialFolder.Recent:
642                         case SpecialFolder.CommonProgramFiles:
643                         case SpecialFolder.System:
644                         case SpecialFolder.NetworkShortcuts:
645                         case SpecialFolder.CommonStartMenu:
646                         case SpecialFolder.CommonPrograms:
647                         case SpecialFolder.CommonStartup:
648                         case SpecialFolder.CommonDesktopDirectory:
649                         case SpecialFolder.PrinterShortcuts:
650                         case SpecialFolder.Windows:
651                         case SpecialFolder.SystemX86:
652                         case SpecialFolder.ProgramFilesX86:
653                         case SpecialFolder.CommonProgramFilesX86:
654                         case SpecialFolder.CommonDocuments:
655                         case SpecialFolder.CommonAdminTools:
656                         case SpecialFolder.AdminTools:
657                         case SpecialFolder.CommonMusic:
658                         case SpecialFolder.CommonPictures:
659                         case SpecialFolder.CommonVideos:
660                         case SpecialFolder.Resources:
661                         case SpecialFolder.LocalizedResources:
662                         case SpecialFolder.CommonOemLinks:
663                         case SpecialFolder.CDBurning:
664                                 return String.Empty;
665                         // This is where data common to all users goes
666                         case SpecialFolder.CommonApplicationData:
667                                 return "/usr/share";
668                         default:
669                                 throw new ArgumentException ("Invalid SpecialFolder");
670                         }
671                 }
672 #endif
673
674                 
675                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
676                 public static string[] GetLogicalDrives ()
677                 {
678                         return GetLogicalDrivesInternal ();
679                 }
680
681 #if !MOBILE
682                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
683                 private static extern void internalBroadcastSettingChange ();
684
685                 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
686                 {
687                         switch (target) {
688                         case EnvironmentVariableTarget.Process:
689                                 return GetEnvironmentVariable (variable);
690                         case EnvironmentVariableTarget.Machine:
691                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
692                                 if (!IsRunningOnWindows)
693                                         return null;
694                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
695                                         object regvalue = env.GetValue (variable);
696                                         return (regvalue == null) ? null : regvalue.ToString ();
697                                 }
698                         case EnvironmentVariableTarget.User:
699                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
700                                 if (!IsRunningOnWindows)
701                                         return null;
702                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
703                                         object regvalue = env.GetValue (variable);
704                                         return (regvalue == null) ? null : regvalue.ToString ();
705                                 }
706                         default:
707                                 throw new ArgumentException ("target");
708                         }
709                 }
710
711                 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
712                 {
713                         IDictionary variables = (IDictionary)new Hashtable ();
714                         switch (target) {
715                         case EnvironmentVariableTarget.Process:
716                                 variables = GetEnvironmentVariables ();
717                                 break;
718                         case EnvironmentVariableTarget.Machine:
719                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
720                                 if (IsRunningOnWindows) {
721                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
722                                                 string[] value_names = env.GetValueNames ();
723                                                 foreach (string value_name in value_names)
724                                                         variables.Add (value_name, env.GetValue (value_name));
725                                         }
726                                 }
727                                 break;
728                         case EnvironmentVariableTarget.User:
729                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
730                                 if (IsRunningOnWindows) {
731                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
732                                                 string[] value_names = env.GetValueNames ();
733                                                 foreach (string value_name in value_names)
734                                                         variables.Add (value_name, env.GetValue (value_name));
735                                         }
736                                 }
737                                 break;
738                         default:
739                                 throw new ArgumentException ("target");
740                         }
741                         return variables;
742                 }
743
744                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
745                 public static void SetEnvironmentVariable (string variable, string value)
746                 {
747                         SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
748                 }
749
750                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
751                 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
752                 {
753                         if (variable == null)
754                                 throw new ArgumentNullException ("variable");
755                         if (variable == String.Empty)
756                                 throw new ArgumentException ("String cannot be of zero length.", "variable");
757                         if (variable.IndexOf ('=') != -1)
758                                 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
759                         if (variable[0] == '\0')
760                                 throw new ArgumentException ("The first char in the string is the null character.", "variable");
761
762                         switch (target) {
763                         case EnvironmentVariableTarget.Process:
764                                 InternalSetEnvironmentVariable (variable, value);
765                                 break;
766                         case EnvironmentVariableTarget.Machine:
767                                 if (!IsRunningOnWindows)
768                                         return;
769                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
770                                         if (String.IsNullOrEmpty (value))
771                                                 env.DeleteValue (variable, false);
772                                         else
773                                                 env.SetValue (variable, value);
774                                         internalBroadcastSettingChange ();
775                                 }
776                                 break;
777                         case EnvironmentVariableTarget.User:
778                                 if (!IsRunningOnWindows)
779                                         return;
780                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
781                                         if (String.IsNullOrEmpty (value))
782                                                 env.DeleteValue (variable, false);
783                                         else
784                                                 env.SetValue (variable, value);
785                                         internalBroadcastSettingChange ();
786                                 }
787                                 break;
788                         default:
789                                 throw new ArgumentException ("target");
790                         }
791                 }
792 #else
793                 public static void SetEnvironmentVariable (string variable, string value)
794                 {
795                         if (variable == null)
796                                 throw new ArgumentNullException ("variable");
797                         if (variable == String.Empty)
798                                 throw new ArgumentException ("String cannot be of zero length.", "variable");
799                         if (variable.IndexOf ('=') != -1)
800                                 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
801                         if (variable[0] == '\0')
802                                 throw new ArgumentException ("The first char in the string is the null character.", "variable");
803
804                         InternalSetEnvironmentVariable (variable, value);
805                 }
806 #endif
807                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
808                 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
809
810                 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
811                 public static void FailFast (string message)
812                 {
813                         throw new NotImplementedException ();
814                 }
815
816                 [SecurityCritical]
817                 public static void FailFast (string message, Exception exception)
818                 {
819                         throw new NotImplementedException ();
820                 }
821
822                 public static bool Is64BitOperatingSystem {
823                         get { return IntPtr.Size == 8; } // FIXME: is this good enough?
824                 }
825
826                 public static int SystemPageSize {
827                         get { return GetPageSize (); }
828                 }
829
830                 public
831                 static bool Is64BitProcess {
832                         get { return IntPtr.Size == 8; }
833                 }
834                 
835                 public static extern int ProcessorCount {
836                         [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
837                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
838                         get;                    
839                 }
840
841                 // private methods
842 #if (MONOTOUCH || MONODROID || XAMMAC)
843                 internal const bool IsRunningOnWindows = false;
844 #else
845                 internal static bool IsRunningOnWindows {
846                         get { return ((int) Platform < 4); }
847                 }
848 #endif
849
850 #if !NET_2_1
851                 //
852                 // Used by gacutil.exe
853                 //
854 #pragma warning disable 169             
855                 private static string GacPath {
856                         get {
857                                 if (Environment.IsRunningOnWindows) {
858                                         /* On windows, we don't know the path where mscorlib.dll will be installed */
859                                         string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
860                                         return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
861                                 }
862
863                                 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
864                         }
865                 }
866 #pragma warning restore 169
867                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
868                 internal extern static string internalGetGacPath ();
869 #endif
870                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
871                 private extern static string [] GetLogicalDrivesInternal ();
872
873                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
874                 private extern static string [] GetEnvironmentVariableNames ();
875
876                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
877                 internal extern static string GetMachineConfigPath ();
878
879                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
880                 internal extern static string internalGetHome ();
881
882                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
883                 internal extern static int GetPageSize ();
884
885                 static internal bool IsUnix {
886                         get {
887                                 int platform = (int) Environment.Platform;
888
889                                 return (platform == 4 || platform == 128 || platform == 6);
890                         }
891                 }
892                 static internal bool IsMacOS {
893                         get {
894                                 return Environment.Platform == PlatformID.MacOSX;
895                         }
896                 }
897         }
898 }
899