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