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