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