[corlib] Changed some MonoIO methods to use SafeHandle.
[mono.git] / mcs / class / corlib / System.IO / MonoIO.cs
1 // System.IO.MonoIO.cs: static interface to native filesystem.
2 //
3 // Author:
4 //   Dan Lewis (dihlewis@yahoo.co.uk)
5 //   Dick Porter (dick@ximian.com)
6 //
7 // (C) 2002
8 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Runtime.CompilerServices;
36 using System.Runtime.InteropServices;
37 using System.Threading;
38 using Microsoft.Win32.SafeHandles;
39 #if NET_2_1
40 using System.IO.IsolatedStorage;
41 #endif
42
43 namespace System.IO
44 {
45         unsafe static class MonoIO {
46                 public const int FileAlreadyExistsHResult = unchecked ((int) 0x80070000) | (int)MonoIOError.ERROR_FILE_EXISTS;
47
48                 public const FileAttributes
49                         InvalidFileAttributes = (FileAttributes)(-1);
50
51                 public static readonly IntPtr
52                         InvalidHandle = (IntPtr)(-1L);
53
54                 // error methods
55                 public static Exception GetException (MonoIOError error)
56                 {
57                         /* This overload is currently only called from
58                          * File.MoveFile(), Directory.Move() and
59                          * Directory.GetCurrentDirectory() -
60                          * everywhere else supplies a path to format
61                          * with the error text.
62                          */
63                         switch(error) {
64                         case MonoIOError.ERROR_ACCESS_DENIED:
65                                 return new UnauthorizedAccessException ("Access to the path is denied.");
66                         case MonoIOError.ERROR_FILE_EXISTS:
67                                 string message = "Cannot create a file that already exist.";
68                                 return new IOException (message, FileAlreadyExistsHResult);
69                         default:
70                                 /* Add more mappings here if other
71                                  * errors trigger the named but empty
72                                  * path bug (see bug 82141.) For
73                                  * everything else, fall through to
74                                  * the other overload
75                                  */
76                                 return GetException (String.Empty, error);
77                         }
78                 }
79
80                 public static Exception GetException (string path,
81                                                       MonoIOError error)
82                 {
83                         string message;
84
85                         switch (error) {
86                         // FIXME: add more exception mappings here
87                         case MonoIOError.ERROR_FILE_NOT_FOUND:
88                                 message = String.Format ("Could not find file \"{0}\"", path);
89                                 return new FileNotFoundException (message, path);
90
91                         case MonoIOError.ERROR_TOO_MANY_OPEN_FILES:
92                                 return new IOException ("Too many open files", unchecked((int)0x80070000) | (int)error);
93                                 
94                         case MonoIOError.ERROR_PATH_NOT_FOUND:
95                                 message = String.Format ("Could not find a part of the path \"{0}\"", path);
96                                 return new DirectoryNotFoundException (message);
97
98                         case MonoIOError.ERROR_ACCESS_DENIED:
99                                 message = String.Format ("Access to the path \"{0}\" is denied.", path);
100                                 return new UnauthorizedAccessException (message);
101
102                         case MonoIOError.ERROR_INVALID_HANDLE:
103                                 message = String.Format ("Invalid handle to path \"{0}\"", path);
104                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
105                         case MonoIOError.ERROR_INVALID_DRIVE:
106                                 message = String.Format ("Could not find the drive  '{0}'. The drive might not be ready or might not be mapped.", path);
107 #if !NET_2_1
108                                 return new DriveNotFoundException (message);
109 #else
110                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
111 #endif
112                         case MonoIOError.ERROR_FILE_EXISTS:
113                                 message = String.Format ("Could not create file \"{0}\". File already exists.", path);
114                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
115
116                         case MonoIOError.ERROR_FILENAME_EXCED_RANGE:
117                                 message = String.Format ("Path is too long. Path: {0}", path); 
118                                 return new PathTooLongException (message);
119
120                         case MonoIOError.ERROR_INVALID_PARAMETER:
121                                 message = String.Format ("Invalid parameter");
122                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
123
124                         case MonoIOError.ERROR_WRITE_FAULT:
125                                 message = String.Format ("Write fault on path {0}", path);
126                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
127
128                         case MonoIOError.ERROR_SHARING_VIOLATION:
129                                 message = String.Format ("Sharing violation on path {0}", path);
130                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
131                                 
132                         case MonoIOError.ERROR_LOCK_VIOLATION:
133                                 message = String.Format ("Lock violation on path {0}", path);
134                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
135                         
136                         case MonoIOError.ERROR_HANDLE_DISK_FULL:
137                                 message = String.Format ("Disk full. Path {0}", path);
138                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
139                         
140                         case MonoIOError.ERROR_DIR_NOT_EMPTY:
141                                 message = String.Format ("Directory {0} is not empty", path);
142                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
143
144                         case MonoIOError.ERROR_ENCRYPTION_FAILED:
145                                 return new IOException ("Encryption failed", unchecked((int)0x80070000) | (int)error);
146
147                         case MonoIOError.ERROR_CANNOT_MAKE:
148                                 message = String.Format ("Path {0} is a directory", path);
149                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
150                                 
151                         case MonoIOError.ERROR_NOT_SAME_DEVICE:
152                                 message = "Source and destination are not on the same device";
153                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
154                                 
155                         default:
156                                 message = String.Format ("Win32 IO returned {0}. Path: {1}", error, path);
157                                 return new IOException (message, unchecked((int)0x80070000) | (int)error);
158                         }
159                 }
160
161                 // directory methods
162
163                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
164                 public extern static bool CreateDirectory (string path, out MonoIOError error);
165
166                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
167                 public extern static bool RemoveDirectory (string path, out MonoIOError error);
168
169                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
170                 public extern static string [] GetFileSystemEntries (string path, string path_with_pattern, int attrs, int mask, out MonoIOError error);
171
172                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
173                 public extern static string GetCurrentDirectory (out MonoIOError error);
174
175                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
176                 public extern static bool SetCurrentDirectory (string path, out MonoIOError error);
177
178                 // file methods
179
180                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
181                 public extern static bool MoveFile (string path, string dest,
182                                                     out MonoIOError error);
183
184                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
185                 public extern static bool CopyFile (string path, string dest,
186                                                     bool overwrite,
187                                                     out MonoIOError error);
188
189                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
190                 public extern static bool DeleteFile (string path,
191                                                       out MonoIOError error);
192
193                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
194                 public extern static bool ReplaceFile (string sourceFileName, 
195                                                        string destinationFileName, 
196                                                        string destinationBackupFileName, 
197                                                        bool ignoreMetadataErrors,
198                                                        out MonoIOError error);
199
200                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
201                 public extern static FileAttributes GetFileAttributes (string path, out MonoIOError error);
202
203                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
204                 public extern static bool SetFileAttributes (string path, FileAttributes attrs, out MonoIOError error);
205
206                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
207                 public extern static MonoFileType GetFileType (SafeHandle safeHandle, out MonoIOError error);
208
209                 //
210                 // Find file methods
211                 //
212                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
213                 public extern static string FindFirst (string path, string pattern, out FileAttributes result_attr, out MonoIOError error, out IntPtr handle);
214                 
215                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
216                 public extern static string FindNext (IntPtr handle, out FileAttributes result_attr, out MonoIOError error);
217                 
218                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
219                 public extern static int FindClose (IntPtr handle);
220                 
221                 public static bool Exists (string path, out MonoIOError error)
222                 {
223                         FileAttributes attrs = GetFileAttributes (path,
224                                                                   out error);
225                         if (attrs == InvalidFileAttributes)
226                                 return false;
227
228                         return true;
229                 }
230
231                 public static bool ExistsFile (string path,
232                                                out MonoIOError error)
233                 {
234                         FileAttributes attrs = GetFileAttributes (path,
235                                                                   out error);
236                         if (attrs == InvalidFileAttributes)
237                                 return false;
238
239                         if ((attrs & FileAttributes.Directory) != 0)
240                                 return false;
241
242                         return true;
243                 }
244
245                 public static bool ExistsDirectory (string path,
246                                                     out MonoIOError error)
247                 {
248                         FileAttributes attrs = GetFileAttributes (path,
249                                                                   out error);
250                                                                   
251                         // Actually, we are looking for a directory, not a file
252                         if (error == MonoIOError.ERROR_FILE_NOT_FOUND)
253                                 error = MonoIOError.ERROR_PATH_NOT_FOUND;
254                                 
255                         if (attrs == InvalidFileAttributes)
256                                 return false;
257
258                         if ((attrs & FileAttributes.Directory) == 0)
259                                 return false;
260
261                         return true;
262                 }
263
264                 public static bool ExistsSymlink (string path,
265                                                   out MonoIOError error)
266                 {
267                         FileAttributes attrs = GetFileAttributes (path,
268                                                                   out error);
269                         if (attrs == InvalidFileAttributes)
270                                 return false;
271                         
272                         if ((attrs & FileAttributes.ReparsePoint) == 0)
273                                 return false;
274
275                         return true;
276                 }
277
278                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
279                 public extern static bool GetFileStat (string path,
280                                                        out MonoIOStat stat,
281                                                        out MonoIOError error);
282
283                 // handle methods
284
285                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
286                 public extern static IntPtr Open (string filename,
287                                                   FileMode mode,
288                                                   FileAccess access,
289                                                   FileShare share,
290                                                   FileOptions options,
291                                                   out MonoIOError error);
292
293                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
294                 public extern static bool Close (IntPtr handle,
295                                                  out MonoIOError error);
296                 
297                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
298                 public extern static int Read (SafeHandle safeHandle, byte [] dest,
299                                                int dest_offset, int count,
300                                                out MonoIOError error);
301                 
302                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
303                 public extern static int Write (SafeHandle safeHandle, [In] byte [] src,
304                                                 int src_offset, int count,
305                                                 out MonoIOError error);
306                 
307                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
308                 public extern static long Seek (SafeHandle safeHandle, long offset,
309                                                 SeekOrigin origin,
310                                                 out MonoIOError error);
311                 
312                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
313                 public extern static bool Flush (SafeHandle safeHandle,
314                                                  out MonoIOError error);
315
316                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
317                 public extern static long GetLength (SafeHandle handle,
318                                                      out MonoIOError error);
319
320                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
321                 public extern static bool SetLength (SafeHandle safeHandle,
322                                                      long length,
323                                                      out MonoIOError error);
324
325                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
326                 public extern static bool SetFileTime (SafeHandle safeHandle,
327                                                        long creation_time,
328                                                        long last_access_time,
329                                                        long last_write_time,
330                                                        out MonoIOError error);
331
332                 public static bool SetFileTime (string path,
333                                                 long creation_time,
334                                                 long last_access_time,
335                                                 long last_write_time,
336                                                 out MonoIOError error)
337                 {
338                         return SetFileTime (path,
339                                 0,
340                                 creation_time,
341                                 last_access_time,
342                                 last_write_time,
343                                 DateTime.MinValue,
344                                 out error);
345                 }
346
347                 public static bool SetCreationTime (string path,
348                                                 DateTime dateTime,
349                                                 out MonoIOError error)
350                 {
351                         return SetFileTime (path, 1, -1, -1, -1, dateTime, out error);
352                 }
353
354                 public static bool SetLastAccessTime (string path,
355                                                 DateTime dateTime,
356                                                 out MonoIOError error)
357                 {
358                         return SetFileTime (path, 2, -1, -1, -1, dateTime, out error);
359                 }
360
361                 public static bool SetLastWriteTime (string path,
362                                                 DateTime dateTime,
363                                                 out MonoIOError error)
364                 {
365                         return SetFileTime (path, 3, -1, -1, -1, dateTime, out error);
366                 }
367
368                 public static bool SetFileTime (string path,
369                                                 int type,
370                                                 long creation_time,
371                                                 long last_access_time,
372                                                 long last_write_time,
373                                                 DateTime dateTime,
374                                                 out MonoIOError error)
375                 {
376                         IntPtr handle;
377                         bool result;
378
379                         handle = Open (path, FileMode.Open,
380                                        FileAccess.ReadWrite,
381                                        FileShare.ReadWrite, FileOptions.None, out error);
382                         if (handle == MonoIO.InvalidHandle)
383                                 return false;
384
385                         switch (type) {
386                         case 1:
387                                 creation_time = dateTime.ToFileTime ();
388                                 break;
389                         case 2:
390                                 last_access_time = dateTime.ToFileTime ();
391                                 break;
392                         case 3:
393                                 last_write_time = dateTime.ToFileTime ();
394                                 break;
395                         }
396
397                         result = SetFileTime (new SafeFileHandle(handle, false), creation_time,
398                                               last_access_time,
399                                               last_write_time, out error);
400
401                         MonoIOError ignore_error;
402                         Close (handle, out ignore_error);
403                         
404                         return result;
405                 }
406
407                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
408                 public extern static void Lock (SafeHandle safeHandle,
409                                                 long position, long length,
410                                                 out MonoIOError error);
411
412                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
413                 public extern static void Unlock (SafeHandle safeHandle,
414                                                   long position, long length,
415                                                   out MonoIOError error);
416
417                 // console handles
418
419                 public extern static IntPtr ConsoleOutput {
420                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
421                         get;
422                 }
423
424                 public extern static IntPtr ConsoleInput {
425                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
426                         get;
427                 }
428
429                 public extern static IntPtr ConsoleError {
430                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
431                         get;
432                 }
433
434                 // pipe handles
435
436                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
437                 public extern static bool CreatePipe (out IntPtr read_handle, out IntPtr write_handle);
438
439                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
440                 public extern static bool DuplicateHandle (IntPtr source_process_handle, IntPtr source_handle,
441                         IntPtr target_process_handle, out IntPtr target_handle, int access, int inherit, int options);
442
443                 // path characters
444
445                 public extern static char VolumeSeparatorChar {
446                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
447                         get;
448                 }
449
450                 public extern static char DirectorySeparatorChar {
451                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
452                         get;
453                 }
454
455                 public extern static char AltDirectorySeparatorChar {
456                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
457                         get;
458                 }
459
460                 public extern static char PathSeparator {
461                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
462                         get;
463                 }
464
465                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
466                 public extern static int GetTempPath(out string path);
467         }
468 }
469