1 // System.IO.MonoIO.cs: static interface to native filesystem.
4 // Dan Lewis (dihlewis@yahoo.co.uk)
5 // Dick Porter (dick@ximian.com)
8 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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.
35 using System
.Runtime
.CompilerServices
;
36 using System
.Runtime
.InteropServices
;
37 using System
.Threading
;
38 using Microsoft
.Win32
.SafeHandles
;
40 using System
.IO
.IsolatedStorage
;
45 unsafe static class MonoIO
{
46 public const int FileAlreadyExistsHResult
= unchecked ((int) 0x80070000) | (int)MonoIOError
.ERROR_FILE_EXISTS
;
48 public const FileAttributes
49 InvalidFileAttributes
= (FileAttributes
)(-1);
51 public static readonly IntPtr
52 InvalidHandle
= (IntPtr
)(-1L);
54 static bool dump_handles
= Environment
.GetEnvironmentVariable ("MONO_DUMP_HANDLES_ON_ERROR_TOO_MANY_OPEN_FILES") != null;
57 public static Exception
GetException (MonoIOError error
)
59 /* This overload is currently only called from
60 * File.MoveFile(), Directory.Move() and
61 * Directory.GetCurrentDirectory() -
62 * everywhere else supplies a path to format
63 * with the error text.
66 case MonoIOError
.ERROR_ACCESS_DENIED
:
67 return new UnauthorizedAccessException ("Access to the path is denied.");
68 case MonoIOError
.ERROR_FILE_EXISTS
:
69 string message
= "Cannot create a file that already exist.";
70 return new IOException (message
, FileAlreadyExistsHResult
);
72 /* Add more mappings here if other
73 * errors trigger the named but empty
74 * path bug (see bug 82141.) For
75 * everything else, fall through to
78 return GetException (String
.Empty
, error
);
82 public static Exception
GetException (string path
,
88 // FIXME: add more exception mappings here
89 case MonoIOError
.ERROR_FILE_NOT_FOUND
:
90 message
= String
.Format ("Could not find file \"{0}\"", path
);
91 return new FileNotFoundException (message
, path
);
93 case MonoIOError
.ERROR_TOO_MANY_OPEN_FILES
:
96 return new IOException ("Too many open files", unchecked((int)0x80070000) | (int)error
);
98 case MonoIOError
.ERROR_PATH_NOT_FOUND
:
99 message
= String
.Format ("Could not find a part of the path \"{0}\"", path
);
100 return new DirectoryNotFoundException (message
);
102 case MonoIOError
.ERROR_ACCESS_DENIED
:
103 message
= String
.Format ("Access to the path \"{0}\" is denied.", path
);
104 return new UnauthorizedAccessException (message
);
106 case MonoIOError
.ERROR_INVALID_HANDLE
:
107 message
= String
.Format ("Invalid handle to path \"{0}\"", path
);
108 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
109 case MonoIOError
.ERROR_INVALID_DRIVE
:
110 message
= String
.Format ("Could not find the drive '{0}'. The drive might not be ready or might not be mapped.", path
);
112 return new DriveNotFoundException (message
);
114 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
116 case MonoIOError
.ERROR_FILE_EXISTS
:
117 message
= String
.Format ("Could not create file \"{0}\". File already exists.", path
);
118 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
120 case MonoIOError
.ERROR_FILENAME_EXCED_RANGE
:
121 message
= String
.Format ("Path is too long. Path: {0}", path
);
122 return new PathTooLongException (message
);
124 case MonoIOError
.ERROR_INVALID_PARAMETER
:
125 message
= String
.Format ("Invalid parameter");
126 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
128 case MonoIOError
.ERROR_WRITE_FAULT
:
129 message
= String
.Format ("Write fault on path {0}", path
);
130 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
132 case MonoIOError
.ERROR_SHARING_VIOLATION
:
133 message
= String
.Format ("Sharing violation on path {0}", path
);
134 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
136 case MonoIOError
.ERROR_LOCK_VIOLATION
:
137 message
= String
.Format ("Lock violation on path {0}", path
);
138 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
140 case MonoIOError
.ERROR_HANDLE_DISK_FULL
:
141 message
= String
.Format ("Disk full. Path {0}", path
);
142 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
144 case MonoIOError
.ERROR_DIR_NOT_EMPTY
:
145 message
= String
.Format ("Directory {0} is not empty", path
);
146 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
148 case MonoIOError
.ERROR_ENCRYPTION_FAILED
:
149 return new IOException ("Encryption failed", unchecked((int)0x80070000) | (int)error
);
151 case MonoIOError
.ERROR_CANNOT_MAKE
:
152 message
= String
.Format ("Path {0} is a directory", path
);
153 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
155 case MonoIOError
.ERROR_NOT_SAME_DEVICE
:
156 message
= "Source and destination are not on the same device";
157 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
159 case MonoIOError
.ERROR_DIRECTORY
:
160 message
= "The directory name is invalid";
161 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
164 message
= String
.Format ("Win32 IO returned {0}. Path: {1}", error
, path
);
165 return new IOException (message
, unchecked((int)0x80070000) | (int)error
);
171 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
172 private unsafe extern static bool CreateDirectory (char* path
, out MonoIOError error
);
174 public static bool CreateDirectory (string path
, out MonoIOError error
)
177 fixed (char* pathChars
= path
) {
178 return CreateDirectory (pathChars
, out error
);
183 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
184 private unsafe extern static bool RemoveDirectory (char* path
, out MonoIOError error
);
186 public static bool RemoveDirectory (string path
, out MonoIOError error
)
189 fixed (char* pathChars
= path
) {
190 return RemoveDirectory (pathChars
, out error
);
195 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
196 public extern static string GetCurrentDirectory (out MonoIOError error
);
198 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
199 private unsafe extern static bool SetCurrentDirectory (char* path
, out MonoIOError error
);
201 public static bool SetCurrentDirectory (string path
, out MonoIOError error
)
204 fixed (char* pathChars
= path
) {
205 return SetCurrentDirectory (pathChars
, out error
);
212 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
213 private unsafe extern static bool MoveFile (char* path
, char* dest
,
214 out MonoIOError error
);
216 public static bool MoveFile (string path
, string dest
,
217 out MonoIOError error
)
220 fixed (char* pathChars
= path
, destChars
= dest
) {
221 return MoveFile (pathChars
, destChars
, out error
);
226 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
227 private unsafe extern static bool CopyFile (char* path
, char* dest
,
229 out MonoIOError error
);
231 public static bool CopyFile (string path
, string dest
,
233 out MonoIOError error
)
236 fixed (char* pathChars
= path
, destChars
= dest
) {
237 return CopyFile (pathChars
, destChars
, overwrite
, out error
);
242 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
243 private unsafe extern static bool DeleteFile (char* path
,
244 out MonoIOError error
);
246 public static bool DeleteFile (string path
,
247 out MonoIOError error
)
250 fixed (char* pathChars
= path
) {
251 return DeleteFile (pathChars
, out error
);
256 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
257 private unsafe extern static bool ReplaceFile (char* sourceFileName
,
258 char* destinationFileName
,
259 char* destinationBackupFileName
,
260 bool ignoreMetadataErrors
,
261 out MonoIOError error
);
263 public static bool ReplaceFile (string sourceFileName
,
264 string destinationFileName
,
265 string destinationBackupFileName
,
266 bool ignoreMetadataErrors
,
267 out MonoIOError error
)
270 fixed (char* sourceFileNameChars
= sourceFileName
,
271 destinationFileNameChars
= destinationFileName
,
272 destinationBackupFileNameChars
= destinationBackupFileName
) {
273 return ReplaceFile (sourceFileNameChars
, destinationFileNameChars
, destinationBackupFileNameChars
, ignoreMetadataErrors
, out error
);
278 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
279 private unsafe extern static FileAttributes
GetFileAttributes (char* path
, out MonoIOError error
);
281 public static FileAttributes
GetFileAttributes (string path
, out MonoIOError error
)
284 fixed (char* pathChars
= path
) {
285 return GetFileAttributes (pathChars
, out error
);
290 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
291 private extern static bool SetFileAttributes (char* path
, FileAttributes attrs
, out MonoIOError error
);
293 public static bool SetFileAttributes (string path
, FileAttributes attrs
, out MonoIOError error
)
296 fixed (char* pathChars
= path
) {
297 return SetFileAttributes (pathChars
, attrs
, out error
);
302 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
303 private extern static MonoFileType
GetFileType (IntPtr handle
, out MonoIOError error
);
305 public static MonoFileType
GetFileType (SafeHandle safeHandle
, out MonoIOError error
)
307 bool release
= false;
309 safeHandle
.DangerousAddRef (ref release
);
310 return GetFileType (safeHandle
.DangerousGetHandle (), out error
);
313 safeHandle
.DangerousRelease ();
321 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
322 private unsafe extern static IntPtr
FindFirstFile (char* pathWithPattern
, out string fileName
, out int fileAttr
, out int error
);
324 public static IntPtr
FindFirstFile (string pathWithPattern
, out string fileName
, out int fileAttr
, out int error
)
327 fixed (char* pathWithPatternChars
= pathWithPattern
) {
328 return FindFirstFile (pathWithPatternChars
, out fileName
, out fileAttr
, out error
);
333 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
334 public extern static bool FindNextFile (IntPtr hnd
, out string fileName
, out int fileAttr
, out int error
);
336 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
337 public extern static bool FindCloseFile (IntPtr hnd
);
339 public static bool Exists (string path
, out MonoIOError error
)
341 FileAttributes attrs
= GetFileAttributes (path
,
343 if (attrs
== InvalidFileAttributes
)
349 public static bool ExistsFile (string path
,
350 out MonoIOError error
)
352 FileAttributes attrs
= GetFileAttributes (path
,
354 if (attrs
== InvalidFileAttributes
)
357 if ((attrs
& FileAttributes
.Directory
) != 0)
363 public static bool ExistsDirectory (string path
,
364 out MonoIOError error
)
366 FileAttributes attrs
= GetFileAttributes (path
,
369 // Actually, we are looking for a directory, not a file
370 if (error
== MonoIOError
.ERROR_FILE_NOT_FOUND
)
371 error
= MonoIOError
.ERROR_PATH_NOT_FOUND
;
373 if (attrs
== InvalidFileAttributes
)
376 if ((attrs
& FileAttributes
.Directory
) == 0)
382 public static bool ExistsSymlink (string path
,
383 out MonoIOError error
)
385 FileAttributes attrs
= GetFileAttributes (path
,
387 if (attrs
== InvalidFileAttributes
)
390 if ((attrs
& FileAttributes
.ReparsePoint
) == 0)
396 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
397 private unsafe extern static bool GetFileStat (char* path
,
399 out MonoIOError error
);
401 public static bool GetFileStat (string path
,
403 out MonoIOError error
)
406 fixed (char* pathChars
= path
) {
407 return GetFileStat (pathChars
, out stat
, out error
);
414 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
415 private unsafe extern static IntPtr
Open (char* filename
,
420 out MonoIOError error
);
422 public static IntPtr
Open (string filename
,
427 out MonoIOError error
)
430 fixed (char* filenameChars
= filename
) {
431 return Open (filenameChars
, mode
, access
, share
, options
, out error
);
436 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
437 private extern static bool Cancel_internal (IntPtr handle
, out MonoIOError error
);
439 internal static bool Cancel (SafeHandle safeHandle
, out MonoIOError error
)
441 bool release
= false;
443 safeHandle
.DangerousAddRef (ref release
);
444 return Cancel_internal (safeHandle
.DangerousGetHandle (), out error
);
447 safeHandle
.DangerousRelease ();
451 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
452 public extern static bool Close (IntPtr handle
,
453 out MonoIOError error
);
455 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
456 private extern static int Read (IntPtr handle
, byte [] dest
,
457 int dest_offset
, int count
,
458 out MonoIOError error
);
460 public static int Read (SafeHandle safeHandle
, byte [] dest
,
461 int dest_offset
, int count
,
462 out MonoIOError error
)
464 bool release
= false;
466 safeHandle
.DangerousAddRef (ref release
);
467 return Read (safeHandle
.DangerousGetHandle (), dest
, dest_offset
, count
, out error
);
470 safeHandle
.DangerousRelease ();
474 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
475 private extern static int Write (IntPtr handle
, [In
] byte [] src
,
476 int src_offset
, int count
,
477 out MonoIOError error
);
479 public static int Write (SafeHandle safeHandle
, byte [] src
,
480 int src_offset
, int count
,
481 out MonoIOError error
)
483 bool release
= false;
485 safeHandle
.DangerousAddRef (ref release
);
486 return Write (safeHandle
.DangerousGetHandle (), src
, src_offset
, count
, out error
);
489 safeHandle
.DangerousRelease ();
493 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
494 private extern static long Seek (IntPtr handle
, long offset
,
496 out MonoIOError error
);
498 public static long Seek (SafeHandle safeHandle
, long offset
,
500 out MonoIOError error
)
502 bool release
= false;
504 safeHandle
.DangerousAddRef (ref release
);
505 return Seek (safeHandle
.DangerousGetHandle (), offset
, origin
, out error
);
508 safeHandle
.DangerousRelease ();
512 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
513 private extern static bool Flush (IntPtr handle
,
514 out MonoIOError error
);
516 public static bool Flush (SafeHandle safeHandle
,
517 out MonoIOError error
)
519 bool release
= false;
521 safeHandle
.DangerousAddRef (ref release
);
522 return Flush (safeHandle
.DangerousGetHandle (), out error
);
525 safeHandle
.DangerousRelease ();
529 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
530 private extern static long GetLength (IntPtr handle
,
531 out MonoIOError error
);
533 public static long GetLength (SafeHandle safeHandle
,
534 out MonoIOError error
)
536 bool release
= false;
538 safeHandle
.DangerousAddRef (ref release
);
539 return GetLength (safeHandle
.DangerousGetHandle (), out error
);
542 safeHandle
.DangerousRelease ();
546 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
547 private extern static bool SetLength (IntPtr handle
,
549 out MonoIOError error
);
551 public static bool SetLength (SafeHandle safeHandle
,
553 out MonoIOError error
)
555 bool release
= false;
557 safeHandle
.DangerousAddRef (ref release
);
558 return SetLength (safeHandle
.DangerousGetHandle (), length
, out error
);
561 safeHandle
.DangerousRelease ();
565 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
566 private extern static bool SetFileTime (IntPtr handle
,
568 long last_access_time
,
569 long last_write_time
,
570 out MonoIOError error
);
572 public static bool SetFileTime (SafeHandle safeHandle
,
574 long last_access_time
,
575 long last_write_time
,
576 out MonoIOError error
)
578 bool release
= false;
580 safeHandle
.DangerousAddRef (ref release
);
581 return SetFileTime (safeHandle
.DangerousGetHandle (), creation_time
, last_access_time
, last_write_time
, out error
);
584 safeHandle
.DangerousRelease ();
588 public static bool SetFileTime (string path
,
590 long last_access_time
,
591 long last_write_time
,
592 out MonoIOError error
)
594 return SetFileTime (path
,
603 public static bool SetCreationTime (string path
,
605 out MonoIOError error
)
607 return SetFileTime (path
, 1, -1, -1, -1, dateTime
, out error
);
610 public static bool SetLastAccessTime (string path
,
612 out MonoIOError error
)
614 return SetFileTime (path
, 2, -1, -1, -1, dateTime
, out error
);
617 public static bool SetLastWriteTime (string path
,
619 out MonoIOError error
)
621 return SetFileTime (path
, 3, -1, -1, -1, dateTime
, out error
);
624 public static bool SetFileTime (string path
,
627 long last_access_time
,
628 long last_write_time
,
630 out MonoIOError error
)
635 handle
= Open (path
, FileMode
.Open
,
636 FileAccess
.ReadWrite
,
637 FileShare
.ReadWrite
, FileOptions
.None
, out error
);
638 if (handle
== MonoIO
.InvalidHandle
)
643 creation_time
= dateTime
.ToFileTime ();
646 last_access_time
= dateTime
.ToFileTime ();
649 last_write_time
= dateTime
.ToFileTime ();
653 result
= SetFileTime (new SafeFileHandle(handle
, false), creation_time
,
655 last_write_time
, out error
);
657 MonoIOError ignore_error
;
658 Close (handle
, out ignore_error
);
663 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
664 private extern static void Lock (IntPtr handle
,
665 long position
, long length
,
666 out MonoIOError error
);
668 public static void Lock (SafeHandle safeHandle
,
669 long position
, long length
,
670 out MonoIOError error
)
672 bool release
= false;
674 safeHandle
.DangerousAddRef (ref release
);
675 Lock (safeHandle
.DangerousGetHandle (), position
, length
, out error
);
678 safeHandle
.DangerousRelease ();
682 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
683 private extern static void Unlock (IntPtr handle
,
684 long position
, long length
,
685 out MonoIOError error
);
687 public static void Unlock (SafeHandle safeHandle
,
688 long position
, long length
,
689 out MonoIOError error
)
691 bool release
= false;
693 safeHandle
.DangerousAddRef (ref release
);
694 Unlock (safeHandle
.DangerousGetHandle (), position
, length
, out error
);
697 safeHandle
.DangerousRelease ();
703 public extern static IntPtr ConsoleOutput
{
704 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
708 public extern static IntPtr ConsoleInput
{
709 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
713 public extern static IntPtr ConsoleError
{
714 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
720 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
721 public extern static bool CreatePipe (out IntPtr read_handle
, out IntPtr write_handle
, out MonoIOError error
);
723 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
724 public extern static bool DuplicateHandle (IntPtr source_process_handle
, IntPtr source_handle
,
725 IntPtr target_process_handle
, out IntPtr target_handle
, int access
, int inherit
, int options
, out MonoIOError error
);
729 public extern static char VolumeSeparatorChar
{
730 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
734 public extern static char DirectorySeparatorChar
{
735 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
739 public extern static char AltDirectorySeparatorChar
{
740 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
744 public extern static char PathSeparator
{
745 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
749 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
750 extern static void DumpHandles ();