Merge pull request #3626 from lateralusX/jlorenss/win-api-family-support-eglib
[mono.git] / mcs / class / corlib / System.IO / File.cs
1 // 
2 // System.IO.File.cs 
3 //
4 // 
5 // Authors:
6 //   Miguel de Icaza (miguel@ximian.com)
7 //   Jim Richardson  (develop@wtfo-guru.com)
8 //   Dan Lewis       (dihlewis@yahoo.co.uk)
9 //   Ville Palo      (vi64pa@kolumbus.fi)
10 //
11 // Copyright 2002 Ximian, Inc. http://www.ximian.com
12 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
13 // Copyright (C) 2004, 2006, 2010 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;
36 using System.Collections.Generic;
37 using System.Diagnostics;
38 using System.Security;
39 using System.Text;
40 using System.Runtime.InteropServices;
41 using System.Security.AccessControl;
42
43 namespace System.IO
44 {
45         [ComVisible (true)]
46         public static class File
47         {
48                 public static void AppendAllText (string path, string contents)
49                 {
50                         using (TextWriter w = new StreamWriter (path, true)) {
51                                 w.Write (contents);
52                         }
53                 }
54
55                 public static void AppendAllText (string path, string contents, Encoding encoding)
56                 {
57                         using (TextWriter w = new StreamWriter (path, true, encoding)) {
58                                 w.Write (contents);
59                         }
60                 }
61
62                 public static StreamWriter AppendText (string path)
63                 {
64                         return new StreamWriter (path, true);
65                 }
66
67                 public static void Copy (string sourceFileName, string destFileName)
68                 {
69                         Copy (sourceFileName, destFileName, false);
70                 }
71
72                 public static void Copy (string sourceFileName, string destFileName, bool overwrite)
73                 {
74                         MonoIOError error;
75
76                         if (sourceFileName == null)
77                                 throw new ArgumentNullException ("sourceFileName");
78                         if (destFileName == null)
79                                 throw new ArgumentNullException ("destFileName");
80                         if (sourceFileName.Length == 0)
81                                 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
82                         if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
83                                 throw new ArgumentException ("The file name is not valid.");
84                         if (destFileName.Length == 0)
85                                 throw new ArgumentException ("An empty file name is not valid.", "destFileName");
86                         if (destFileName.Trim ().Length == 0 || destFileName.IndexOfAny (Path.InvalidPathChars) != -1)
87                                 throw new ArgumentException ("The file name is not valid.");
88
89                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
90
91                         if (!MonoIO.Exists (sourceFileName, out error))
92                                 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), sourceFileName);
93                         if ((GetAttributes (sourceFileName) & FileAttributes.Directory) == FileAttributes.Directory)
94                                 throw new ArgumentException (Locale.GetText ("{0} is a directory", sourceFileName));
95
96                         if (MonoIO.Exists (destFileName, out error)) {
97                                 if ((GetAttributes (destFileName) & FileAttributes.Directory) == FileAttributes.Directory)
98                                         throw new ArgumentException (Locale.GetText ("{0} is a directory", destFileName));
99                                 if (!overwrite)
100                                         throw new IOException (Locale.GetText ("{0} already exists", destFileName));
101                         }
102
103                         string DirName = Path.GetDirectoryName (destFileName);
104                         if (DirName != String.Empty && !Directory.Exists (DirName))
105                                 throw new DirectoryNotFoundException (Locale.GetText ("Destination directory not found: {0}",DirName));
106
107                         if (!MonoIO.CopyFile (sourceFileName, destFileName, overwrite, out error)) {
108                                 string p = Locale.GetText ("{0}\" or \"{1}", sourceFileName, destFileName);
109                                 throw MonoIO.GetException (p, error);
110                         }
111                 }
112
113                 internal static String InternalCopy (String sourceFileName, String destFileName, bool overwrite, bool checkHost)
114                 {
115                         String fullSourceFileName = Path.GetFullPathInternal(sourceFileName);
116                         String fullDestFileName = Path.GetFullPathInternal(destFileName);
117
118                         MonoIOError error;
119
120                         if (!MonoIO.CopyFile (fullSourceFileName, fullDestFileName, overwrite, out error)) {
121                                 string p = Locale.GetText ("{0}\" or \"{1}", sourceFileName, destFileName);
122                                 throw MonoIO.GetException (p, error);
123                         }
124
125                         return fullDestFileName;
126                 }
127
128                 public static FileStream Create (string path)
129                 {
130                         return Create (path, 8192);
131                 }
132
133                 public static FileStream Create (string path, int bufferSize)
134                 {
135                         return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
136                                 FileShare.None, bufferSize);
137                 }
138
139                 [MonoLimitation ("FileOptions are ignored")]
140                 public static FileStream Create (string path, int bufferSize,
141                                                  FileOptions options)
142                 {
143                         return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
144                                 FileShare.None, bufferSize, options);
145                 }
146
147                 [MonoLimitation ("FileOptions and FileSecurity are ignored")]
148                 public static FileStream Create (string path, int bufferSize,
149                                                  FileOptions options,
150                                                  FileSecurity fileSecurity)
151                 {
152                         return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
153                                 FileShare.None, bufferSize, options);
154                 }
155
156                 public static StreamWriter CreateText (string path)
157                 {
158                         return new StreamWriter (path, false);
159                 }
160
161                 public static void Delete (string path)
162                 {
163                         Path.Validate (path);
164                         if (Directory.Exists (path))
165                                 throw new UnauthorizedAccessException(Locale.GetText ("{0} is a directory", path));
166
167                         string DirName = Path.GetDirectoryName(path);
168                         if (DirName != String.Empty && !Directory.Exists (DirName))
169                                 throw new DirectoryNotFoundException (Locale.GetText ("Could not find a part of the path \"{0}\".", path));
170
171                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
172
173                         MonoIOError error;
174                         
175                         if (!MonoIO.DeleteFile (path, out error)){
176                                 if (error != MonoIOError.ERROR_FILE_NOT_FOUND)
177                                         throw MonoIO.GetException (path, error);
178                         }
179                 }
180
181                 public static bool Exists (string path)
182                 {
183                         // For security reasons no exceptions are
184                         // thrown, only false is returned if there is
185                         // any problem with the path or permissions.
186                         // Minimizes what information can be
187                         // discovered by using this method.
188                         if (String.IsNullOrWhiteSpace (path) || path.IndexOfAny(Path.InvalidPathChars) >= 0)
189                                 return false;
190
191                         // on Moonlight this does not throw but returns false
192                         if (!SecurityManager.CheckElevatedPermissions ())
193                                 return false;
194
195                         MonoIOError error;
196                         return MonoIO.ExistsFile (path, out error);
197                 }
198
199                 public static FileSecurity GetAccessControl (string path)
200                 {
201                         // AccessControlSections.Audit requires special permissions.
202                         return GetAccessControl (path,
203                                                  AccessControlSections.Owner |
204                                                  AccessControlSections.Group |
205                                                  AccessControlSections.Access);
206                 }
207                 
208                 public static FileSecurity GetAccessControl (string path, AccessControlSections includeSections)
209                 {
210                         return new FileSecurity (path, includeSections);
211                 }
212
213                 public static FileAttributes GetAttributes (string path)
214                 {
215                         Path.Validate (path);
216                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
217
218                         MonoIOError error;
219                         FileAttributes attrs;
220                         
221                         attrs = MonoIO.GetFileAttributes (path, out error);
222                         if (error != MonoIOError.ERROR_SUCCESS)
223                                 throw MonoIO.GetException (path, error);
224                         return attrs;
225                 }
226
227                 public static DateTime GetCreationTime (string path)
228                 {
229                         MonoIOStat stat;
230                         MonoIOError error;
231                         Path.Validate (path);
232                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
233
234                         if (!MonoIO.GetFileStat (path, out stat, out error)) {
235                                 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
236                                         return DefaultLocalFileTime;
237                                 else
238                                         throw new IOException (path);
239                         }
240                         return DateTime.FromFileTime (stat.CreationTime);
241                 }
242
243                 public static DateTime GetCreationTimeUtc (string path)
244                 {
245                         return GetCreationTime (path).ToUniversalTime ();
246                 }
247
248                 public static DateTime GetLastAccessTime (string path)
249                 {
250                         MonoIOStat stat;
251                         MonoIOError error;
252                         Path.Validate (path);
253                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
254
255                         if (!MonoIO.GetFileStat (path, out stat, out error)) {
256                                 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
257                                         return DefaultLocalFileTime;
258                                 else
259                                         throw new IOException (path);
260                         }
261                         return DateTime.FromFileTime (stat.LastAccessTime);
262                 }
263
264                 public static DateTime GetLastAccessTimeUtc (string path)
265                 {
266                         return GetLastAccessTime (path).ToUniversalTime ();
267                 }
268
269                 public static DateTime GetLastWriteTime (string path)
270                 {
271                         MonoIOStat stat;
272                         MonoIOError error;
273                         Path.Validate (path);
274                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
275
276                         if (!MonoIO.GetFileStat (path, out stat, out error)) {
277                                 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
278                                         return DefaultLocalFileTime;
279                                 else
280                                         throw new IOException (path);
281                         }
282                         return DateTime.FromFileTime (stat.LastWriteTime);
283                 }
284
285                 public static DateTime GetLastWriteTimeUtc (string path)
286                 {
287                         return GetLastWriteTime (path).ToUniversalTime ();
288                 }
289
290                 public static void Move (string sourceFileName, string destFileName)
291                 {
292                         if (sourceFileName == null)
293                                 throw new ArgumentNullException ("sourceFileName");
294                         if (destFileName == null)
295                                 throw new ArgumentNullException ("destFileName");
296                         if (sourceFileName.Length == 0)
297                                 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
298                         if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
299                                 throw new ArgumentException ("The file name is not valid.");
300                         if (destFileName.Length == 0)
301                                 throw new ArgumentException ("An empty file name is not valid.", "destFileName");
302                         if (destFileName.Trim ().Length == 0 || destFileName.IndexOfAny (Path.InvalidPathChars) != -1)
303                                 throw new ArgumentException ("The file name is not valid.");
304
305                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
306
307                         MonoIOError error;
308                         if (!MonoIO.Exists (sourceFileName, out error))
309                                 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), sourceFileName);
310
311                         // Don't check for this error here to allow the runtime
312                         // to check if sourceFileName and destFileName are equal.
313                         // Comparing sourceFileName and destFileName is not enough.
314                         //if (MonoIO.Exists (destFileName, out error))
315                         //      throw new IOException (Locale.GetText ("{0} already exists", destFileName));
316
317                         string DirName;
318                         DirName = Path.GetDirectoryName (destFileName);
319                         if (DirName != String.Empty && !Directory.Exists (DirName))
320                                 throw new DirectoryNotFoundException (Locale.GetText ("Could not find a part of the path."));
321
322                         if (!MonoIO.MoveFile (sourceFileName, destFileName, out error)) {
323                                 if (error == MonoIOError.ERROR_ALREADY_EXISTS)
324                                         throw MonoIO.GetException (error);
325                                 else if (error == MonoIOError.ERROR_SHARING_VIOLATION)
326                                         throw MonoIO.GetException (sourceFileName, error);
327                                 
328                                 throw MonoIO.GetException (error);
329                         }
330                 }
331                 
332                 public static FileStream Open (string path, FileMode mode)
333                 {
334                         return new FileStream (path, mode, mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite, FileShare.None);
335                 }
336                 
337                 public static FileStream Open (string path, FileMode mode, FileAccess access)
338                 {
339                         return new FileStream (path, mode, access, FileShare.None);
340                 }
341
342                 public static FileStream Open (string path, FileMode mode, FileAccess access,
343                                                FileShare share)
344                 {
345                         return new FileStream (path, mode, access, share);
346                 }
347                 
348                 public static FileStream OpenRead (string path)
349                 {
350                         return new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.Read);
351                 }
352
353                 public static StreamReader OpenText (string path)
354                 {
355                         return new StreamReader (path);
356                 }
357
358                 public static FileStream OpenWrite (string path)
359                 {
360                         return new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
361                 }
362
363                 public static void Replace (string sourceFileName,
364                                             string destinationFileName,
365                                             string destinationBackupFileName)
366                 {
367                         Replace (sourceFileName, destinationFileName, destinationBackupFileName, false);
368                 }
369                 
370                 public static void Replace (string sourceFileName,
371                                             string destinationFileName,
372                                             string destinationBackupFileName,
373                                             bool ignoreMetadataErrors)
374                 {
375                         MonoIOError error;
376
377                         if (sourceFileName == null)
378                                 throw new ArgumentNullException ("sourceFileName");
379                         if (destinationFileName == null)
380                                 throw new ArgumentNullException ("destinationFileName");
381                         if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
382                                 throw new ArgumentException ("sourceFileName");
383                         if (destinationFileName.Trim ().Length == 0 || destinationFileName.IndexOfAny (Path.InvalidPathChars) != -1)
384                                 throw new ArgumentException ("destinationFileName");
385
386                         string fullSource = Path.GetFullPath (sourceFileName);
387                         string fullDest = Path.GetFullPath (destinationFileName);
388                         if (MonoIO.ExistsDirectory (fullSource, out error))
389                                 throw new IOException (Locale.GetText ("{0} is a directory", sourceFileName));
390                         if (MonoIO.ExistsDirectory (fullDest, out error))
391                                 throw new IOException (Locale.GetText ("{0} is a directory", destinationFileName));
392
393                         if (!Exists (fullSource))
394                                 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), 
395                                                                  sourceFileName);
396                         if (!Exists (fullDest))
397                                 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", destinationFileName), 
398                                                                  destinationFileName);
399                         if (fullSource == fullDest) 
400                                 throw new IOException (Locale.GetText ("Source and destination arguments are the same file."));
401
402                         string fullBackup = null;
403                         if (destinationBackupFileName != null) {
404                                 if (destinationBackupFileName.Trim ().Length == 0 || 
405                                     destinationBackupFileName.IndexOfAny (Path.InvalidPathChars) != -1)
406                                         throw new ArgumentException ("destinationBackupFileName");
407
408                                 fullBackup = Path.GetFullPath (destinationBackupFileName);
409                                 if (MonoIO.ExistsDirectory (fullBackup, out error))
410                                         throw new IOException (Locale.GetText ("{0} is a directory", destinationBackupFileName));
411                                 if (fullSource == fullBackup)
412                                         throw new IOException (Locale.GetText ("Source and backup arguments are the same file."));
413                                 if (fullDest == fullBackup)
414                                         throw new IOException (Locale.GetText (
415                                                                "Destination and backup arguments are the same file."));
416                         }
417
418                         var attrs = GetAttributes (fullDest);
419
420                         // TODO: Should be done in wapi, win32 api handles this already
421                         if ((attrs & FileAttributes.ReadOnly) != 0)
422                                 throw MonoIO.GetException (MonoIOError.ERROR_ACCESS_DENIED);
423
424                         if (!MonoIO.ReplaceFile (fullSource, fullDest, fullBackup, 
425                                                  ignoreMetadataErrors, out error)) {
426                                 throw MonoIO.GetException (error);
427                         }
428                 }
429
430                 public static void SetAccessControl (string path,
431                                                      FileSecurity fileSecurity)
432                 {
433                         if (null == fileSecurity)
434                                 throw new ArgumentNullException ("fileSecurity");
435
436                         fileSecurity.PersistModifications (path);
437                 }
438
439                 public static void SetAttributes (string path,
440                                                   FileAttributes fileAttributes)
441                 {
442                         MonoIOError error;
443                         Path.Validate (path);
444
445                         if (!MonoIO.SetFileAttributes (path, fileAttributes, out error))
446                                 throw MonoIO.GetException (path, error);
447                 }
448
449                 public static void SetCreationTime (string path, DateTime creationTime)
450                 {
451                         MonoIOError error;
452                         Path.Validate (path);
453                         if (!MonoIO.Exists (path, out error))
454                                 throw MonoIO.GetException (path, error);
455                         if (!MonoIO.SetCreationTime (path, creationTime, out error))
456                                 throw MonoIO.GetException (path, error);
457                 }
458
459                 public static void SetCreationTimeUtc (string path, DateTime creationTimeUtc)
460                 {
461                         SetCreationTime (path, creationTimeUtc.ToLocalTime ());
462                 }
463
464                 public static void SetLastAccessTime (string path, DateTime lastAccessTime)
465                 {
466                         MonoIOError error;
467                         Path.Validate (path);
468                         if (!MonoIO.Exists (path, out error))
469                                 throw MonoIO.GetException (path, error);
470                         if (!MonoIO.SetLastAccessTime (path, lastAccessTime, out error))
471                                 throw MonoIO.GetException (path, error);
472                 }
473
474                 public static void SetLastAccessTimeUtc (string path, DateTime lastAccessTimeUtc)
475                 {
476                         SetLastAccessTime (path, lastAccessTimeUtc.ToLocalTime ());
477                 }
478
479                 public static void SetLastWriteTime (string path,
480                                                      DateTime lastWriteTime)
481                 {
482                         MonoIOError error;
483                         Path.Validate (path);
484                         if (!MonoIO.Exists (path, out error))
485                                 throw MonoIO.GetException (path, error);
486                         if (!MonoIO.SetLastWriteTime (path, lastWriteTime, out error))
487                                 throw MonoIO.GetException (path, error);
488                 }
489
490                 public static void SetLastWriteTimeUtc (string path,
491                                                      DateTime lastWriteTimeUtc)
492                 {
493                         SetLastWriteTime (path, lastWriteTimeUtc.ToLocalTime ());
494                 }
495
496                 //
497                 // The documentation for this method is most likely wrong, it
498                 // talks about doing a "binary read", but the remarks say
499                 // that this "detects the encoding".
500                 //
501                 // This can not detect and do anything useful with the encoding
502                 // since the result is a byte [] not a char [].
503                 //
504                 public static byte [] ReadAllBytes (string path)
505                 {
506                         using (FileStream s = OpenRead (path)) {
507                                 long size = s.Length;
508                                 // limited to 2GB according to http://msdn.microsoft.com/en-us/library/system.io.file.readallbytes.aspx
509                                 if (size > Int32.MaxValue)
510                                         throw new IOException ("Reading more than 2GB with this call is not supported");
511
512                                 int pos = 0;
513                                 int count = (int) size;
514                                 byte [] result = new byte [size];
515                                 while (count > 0) {
516                                         int n = s.Read (result, pos, count);
517                                         if (n == 0)
518                                                 throw new IOException ("Unexpected end of stream");
519                                         pos += n;
520                                         count -= n;
521                                 }
522                                 return result;
523                         }
524                 }
525
526                 public static string [] ReadAllLines (string path)
527                 {
528                         using (StreamReader reader = File.OpenText (path)) {
529                                 return ReadAllLines (reader);
530                         }
531                 }
532
533                 public static string [] ReadAllLines (string path, Encoding encoding)
534                 {
535                         using (StreamReader reader = new StreamReader (path, encoding)) {
536                                 return ReadAllLines (reader);
537                         }
538                 }
539
540                 static string [] ReadAllLines (StreamReader reader)
541                 {
542                         List<string> list = new List<string> ();
543                         while (!reader.EndOfStream)
544                                 list.Add (reader.ReadLine ());
545                         return list.ToArray ();
546                 }
547
548                 public static string ReadAllText (string path)
549                 {
550                         using (StreamReader sr = new StreamReader (path)) {
551                                 return sr.ReadToEnd ();
552                         }
553                 }
554
555                 public static string ReadAllText (string path, Encoding encoding)
556                 {
557                         using (StreamReader sr = new StreamReader (path, encoding)) {
558                                 return sr.ReadToEnd ();
559                         }
560                 }
561
562                 public static void WriteAllBytes (string path, byte [] bytes)
563                 {
564                         using (Stream stream = File.Create (path)) {
565                                 stream.Write (bytes, 0, bytes.Length);
566                         }
567                 }
568
569                 public static void WriteAllLines (string path, string [] contents)
570                 {
571                         using (StreamWriter writer = new StreamWriter (path)) {
572                                 WriteAllLines (writer, contents);
573                         }
574                 }
575
576                 public static void WriteAllLines (string path, string [] contents, Encoding encoding)
577                 {
578                         using (StreamWriter writer = new StreamWriter (path, false, encoding)) {
579                                 WriteAllLines (writer, contents);
580                         }
581                 }
582
583                 static void WriteAllLines (StreamWriter writer, string [] contents)
584                 {
585                         foreach (string line in contents)
586                                 writer.WriteLine (line);
587                 }
588
589                 public static void WriteAllText (string path, string contents)
590                 {
591                         WriteAllText (path, contents, EncodingHelper.UTF8Unmarked);
592                 }
593
594                 public static void WriteAllText (string path, string contents, Encoding encoding)
595                 {
596                         using (StreamWriter sw = new StreamWriter (path, false, encoding)) {
597                                 sw.Write (contents);
598                         }
599                 }
600
601                 static DateTime? defaultLocalFileTime;
602                 static DateTime DefaultLocalFileTime {
603                         get {
604                                 if (defaultLocalFileTime == null)
605                                         defaultLocalFileTime = new DateTime (1601, 1, 1).ToLocalTime ();
606                                         
607                                 return defaultLocalFileTime.Value;
608                         }
609                 }
610
611
612                 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
613                 public static void Encrypt (string path)
614                 {
615                         // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
616                         // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
617                         // we throw the same (instead of a NotImplementedException) because most code should already be
618                         // handling this exception to work properly.
619                         throw new NotSupportedException (Locale.GetText ("File encryption isn't supported on any file system."));
620                 }
621
622                 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
623                 public static void Decrypt (string path)
624                 {
625                         // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
626                         // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
627                         // we throw the same (instead of a NotImplementedException) because most code should already be
628                         // handling this exception to work properly.
629                         throw new NotSupportedException (Locale.GetText ("File encryption isn't supported on any file system."));
630                 }
631
632                 public static IEnumerable<string> ReadLines (string path)
633                 {
634                         return ReadLines (File.OpenText (path));
635                 }
636
637                 public static IEnumerable<string> ReadLines (string path, Encoding encoding)
638                 {
639                         return ReadLines (new StreamReader (path, encoding));
640                 }
641
642                 // refactored in order to avoid compiler-generated names for Moonlight tools
643                 static IEnumerable<string> ReadLines (StreamReader reader)
644                 {
645                         using (reader) {
646                                 string s;
647                                 while ((s = reader.ReadLine ()) != null) {
648                                         yield return s;
649                                 }
650                         }
651                 }
652
653                 public static void AppendAllLines (string path, IEnumerable<string> contents)
654                 {
655                         Path.Validate (path);
656
657                         if (contents == null)
658                                 return;
659
660                         using (TextWriter w = new StreamWriter (path, true)) {
661                                 foreach (var line in contents)
662                                         w.WriteLine (line);
663                         }
664                 }
665
666                 public static void AppendAllLines (string path, IEnumerable<string> contents, Encoding encoding)
667                 {
668                         Path.Validate (path);
669
670                         if (contents == null)
671                                 return;
672
673                         using (TextWriter w = new StreamWriter (path, true, encoding)) {
674                                 foreach (var line in contents)
675                                         w.WriteLine (line);
676                         }
677                 }
678
679                 public static void WriteAllLines (string path, IEnumerable<string> contents)
680                 {
681                         Path.Validate (path);
682
683                         if (contents == null)
684                                 return;
685
686                         using (TextWriter w = new StreamWriter (path, false)) {
687                                 foreach (var line in contents)
688                                         w.WriteLine (line);
689                         }
690                 }
691
692                 public static void WriteAllLines (string path, IEnumerable<string> contents, Encoding encoding)
693                 {
694                         Path.Validate (path);
695
696                         if (contents == null)
697                                 return;
698
699                         using (TextWriter w = new StreamWriter (path, false, encoding)) {
700                                 foreach (var line in contents)
701                                         w.WriteLine (line);
702                         }
703                 }
704
705                 internal static int FillAttributeInfo (String path, ref MonoIOStat data, bool tryagain, bool returnErrorOnNotFound)
706                 {
707                         if (tryagain)
708                                 throw new NotImplementedException ();
709
710                         MonoIOError error;
711                         MonoIO.GetFileStat (path, out data, out error);
712
713                         if (!returnErrorOnNotFound && (error == MonoIOError.ERROR_FILE_NOT_FOUND || error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_NOT_READY)) {
714                                 data = default (MonoIOStat);
715                                 data.fileAttributes = (FileAttributes) (-1);
716                                 return 0;
717                         }
718
719                         return (int) error;
720                 }
721         }
722 }