[w32file] Push win32 specific error to win32 specific implementation (#5665)
[mono.git] / mono / metadata / w32file.c
1 /**
2  * \file
3  * File IO internal calls
4  *
5  * Author:
6  *      Dick Porter (dick@ximian.com)
7  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14
15 #include <config.h>
16
17 #include <glib.h>
18 #include <string.h>
19 #include <errno.h>
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
23 #ifdef HAVE_SYS_STAT_H
24 #include <sys/stat.h>
25 #endif
26 #ifdef HAVE_SYS_TYPES_H
27 #include <sys/types.h>
28 #endif
29
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/w32file.h>
32 #include <mono/metadata/w32error.h>
33 #include <mono/metadata/w32file-internals.h>
34 #include <mono/metadata/exception.h>
35 #include <mono/metadata/appdomain.h>
36 #include <mono/metadata/marshal.h>
37 #include <mono/utils/strenc.h>
38 #include <utils/mono-io-portability.h>
39 #include <mono/metadata/w32handle.h>
40 #include <mono/utils/w32api.h>
41
42 #undef DEBUG
43
44 /* conversion functions */
45
46 static guint32 convert_mode(MonoFileMode mono_mode)
47 {
48         guint32 mode;
49
50         switch(mono_mode) {
51         case FileMode_CreateNew:
52                 mode=CREATE_NEW;
53                 break;
54         case FileMode_Create:
55                 mode=CREATE_ALWAYS;
56                 break;
57         case FileMode_Open:
58                 mode=OPEN_EXISTING;
59                 break;
60         case FileMode_OpenOrCreate:
61                 mode=OPEN_ALWAYS;
62                 break;
63         case FileMode_Truncate:
64                 mode=TRUNCATE_EXISTING;
65                 break;
66         case FileMode_Append:
67                 mode=OPEN_ALWAYS;
68                 break;
69         default:
70                 g_warning("System.IO.FileMode has unknown value 0x%x",
71                           mono_mode);
72                 /* Safe fallback */
73                 mode=OPEN_EXISTING;
74         }
75         
76         return(mode);
77 }
78
79 static guint32 convert_access(MonoFileAccess mono_access)
80 {
81         guint32 access;
82         
83         switch(mono_access) {
84         case FileAccess_Read:
85                 access=GENERIC_READ;
86                 break;
87         case FileAccess_Write:
88                 access=GENERIC_WRITE;
89                 break;
90         case FileAccess_ReadWrite:
91                 access=GENERIC_READ|GENERIC_WRITE;
92                 break;
93         default:
94                 g_warning("System.IO.FileAccess has unknown value 0x%x",
95                           mono_access);
96                 /* Safe fallback */
97                 access=GENERIC_READ;
98         }
99         
100         return(access);
101 }
102
103 static guint32 convert_share(MonoFileShare mono_share)
104 {
105         guint32 share = 0;
106         
107         if (mono_share & FileShare_Read) {
108                 share |= FILE_SHARE_READ;
109         }
110         if (mono_share & FileShare_Write) {
111                 share |= FILE_SHARE_WRITE;
112         }
113         if (mono_share & FileShare_Delete) {
114                 share |= FILE_SHARE_DELETE;
115         }
116         
117         if (mono_share & ~(FileShare_Read|FileShare_Write|FileShare_Delete)) {
118                 g_warning("System.IO.FileShare has unknown value 0x%x",
119                           mono_share);
120                 /* Safe fallback */
121                 share=0;
122         }
123
124         return(share);
125 }
126
127 #if 0
128 static guint32 convert_stdhandle(guint32 fd)
129 {
130         guint32 stdhandle;
131         
132         switch(fd) {
133         case 0:
134                 stdhandle=STD_INPUT_HANDLE;
135                 break;
136         case 1:
137                 stdhandle=STD_OUTPUT_HANDLE;
138                 break;
139         case 2:
140                 stdhandle=STD_ERROR_HANDLE;
141                 break;
142         default:
143                 g_warning("unknown standard file descriptor %d", fd);
144                 stdhandle=STD_INPUT_HANDLE;
145         }
146         
147         return(stdhandle);
148 }
149 #endif
150
151 static guint32 convert_seekorigin(MonoSeekOrigin origin)
152 {
153         guint32 w32origin;
154         
155         switch(origin) {
156         case SeekOrigin_Begin:
157                 w32origin=FILE_BEGIN;
158                 break;
159         case SeekOrigin_Current:
160                 w32origin=FILE_CURRENT;
161                 break;
162         case SeekOrigin_End:
163                 w32origin=FILE_END;
164                 break;
165         default:
166                 g_warning("System.IO.SeekOrigin has unknown value 0x%x",
167                           origin);
168                 /* Safe fallback */
169                 w32origin=FILE_CURRENT;
170         }
171         
172         return(w32origin);
173 }
174
175 /* Managed file attributes have nearly but not quite the same values
176  * as the w32 equivalents.
177  */
178 static guint32 convert_attrs(MonoFileAttributes attrs)
179 {
180         if(attrs & FileAttributes_Encrypted) {
181                 attrs = (MonoFileAttributes)(attrs | FILE_ATTRIBUTE_ENCRYPTED);
182         }
183         
184         return(attrs);
185 }
186
187 /* System.IO.MonoIO internal calls */
188
189 MonoBoolean
190 ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
191 {
192         gboolean ret;
193         
194         *error=ERROR_SUCCESS;
195         
196         ret=mono_w32file_create_directory (mono_string_chars (path));
197         if(ret==FALSE) {
198                 *error=mono_w32error_get_last ();
199         }
200
201         return(ret);
202 }
203
204 MonoBoolean
205 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
206 {
207         gboolean ret;
208         
209         *error=ERROR_SUCCESS;
210         
211         ret=mono_w32file_remove_directory (mono_string_chars (path));
212         if(ret==FALSE) {
213                 *error=mono_w32error_get_last ();
214         }
215
216         return(ret);
217 }
218
219 HANDLE
220 ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path_with_pattern, MonoString **file_name, gint32 *file_attr, gint32 *ioerror)
221 {
222         HANDLE hnd;
223         WIN32_FIND_DATA data;
224         MonoError error;
225
226         hnd = mono_w32file_find_first (mono_string_chars (path_with_pattern), &data);
227
228         if (hnd == INVALID_HANDLE_VALUE) {
229                 *file_name = NULL;
230                 *file_attr = 0;
231                 *ioerror = mono_w32error_get_last ();
232                 return hnd;
233         }
234
235         mono_gc_wbarrier_generic_store (file_name, (MonoObject*) mono_string_from_utf16_checked (data.cFileName, &error));
236         mono_error_set_pending_exception (&error);
237
238         *file_attr = data.dwFileAttributes;
239         *ioerror = ERROR_SUCCESS;
240
241         return hnd;
242 }
243
244 MonoBoolean
245 ves_icall_System_IO_MonoIO_FindNextFile (HANDLE hnd, MonoString **file_name, gint32 *file_attr, gint32 *ioerror)
246 {
247         MonoBoolean res;
248         WIN32_FIND_DATA data;
249         MonoError error;
250
251         res = mono_w32file_find_next (hnd, &data);
252
253         if (res == FALSE) {
254                 *file_name = NULL;
255                 *file_attr = 0;
256                 *ioerror = mono_w32error_get_last ();
257                 return res;
258         }
259
260         mono_gc_wbarrier_generic_store (file_name, (MonoObject*) mono_string_from_utf16_checked (data.cFileName, &error));
261         mono_error_set_pending_exception (&error);
262
263         *file_attr = data.dwFileAttributes;
264         *ioerror = ERROR_SUCCESS;
265
266         return res;
267 }
268
269 MonoBoolean
270 ves_icall_System_IO_MonoIO_FindCloseFile (HANDLE hnd)
271 {
272         return mono_w32file_find_close (hnd);
273 }
274
275 MonoString *
276 ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *io_error)
277 {
278         MonoError error;
279         MonoString *result;
280         gunichar2 *buf;
281         int len, res_len;
282
283         len = MAX_PATH + 1; /*FIXME this is too smal under most unix systems.*/
284         buf = g_new (gunichar2, len);
285         
286         error_init (&error);
287         *io_error=ERROR_SUCCESS;
288         result = NULL;
289
290         res_len = mono_w32file_get_cwd (len, buf);
291         if (res_len > len) { /*buf is too small.*/
292                 int old_res_len = res_len;
293                 g_free (buf);
294                 buf = g_new (gunichar2, res_len);
295                 res_len = mono_w32file_get_cwd (res_len, buf) == old_res_len;
296         }
297         
298         if (res_len) {
299                 len = 0;
300                 while (buf [len])
301                         ++ len;
302
303                 result = mono_string_new_utf16_checked (mono_domain_get (), buf, len, &error);
304         } else {
305                 *io_error=mono_w32error_get_last ();
306         }
307
308         g_free (buf);
309         mono_error_set_pending_exception (&error);
310         return result;
311 }
312
313 MonoBoolean
314 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
315                                                 gint32 *error)
316 {
317         gboolean ret;
318         
319         *error=ERROR_SUCCESS;
320         
321         ret=mono_w32file_set_cwd (mono_string_chars (path));
322         if(ret==FALSE) {
323                 *error=mono_w32error_get_last ();
324         }
325         
326         return(ret);
327 }
328
329 MonoBoolean
330 ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest, gint32 *error)
331 {
332         *error=ERROR_SUCCESS;
333         return mono_w32file_move (mono_string_chars (path), mono_string_chars (dest), error);
334 }
335
336 MonoBoolean
337 ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
338                                         MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
339                                         gint32 *error)
340 {
341         gunichar2 *utf16_sourceFileName = NULL, *utf16_destinationFileName = NULL, *utf16_destinationBackupFileName = NULL;
342         guint32 replaceFlags = REPLACEFILE_WRITE_THROUGH;
343
344         if (sourceFileName)
345                 utf16_sourceFileName = mono_string_chars (sourceFileName);
346         if (destinationFileName)
347                 utf16_destinationFileName = mono_string_chars (destinationFileName);
348         if (destinationBackupFileName)
349                 utf16_destinationBackupFileName = mono_string_chars (destinationBackupFileName);
350
351         *error = ERROR_SUCCESS;
352         if (ignoreMetadataErrors)
353                 replaceFlags |= REPLACEFILE_IGNORE_MERGE_ERRORS;
354
355         /* FIXME: source and destination file names must not be NULL, but apparently they might be! */
356         return mono_w32file_replace (utf16_destinationFileName, utf16_sourceFileName,
357                                           utf16_destinationBackupFileName, replaceFlags, error);
358 }
359
360 MonoBoolean
361 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
362                                      MonoBoolean overwrite, gint32 *error)
363 {
364         *error=ERROR_SUCCESS;
365         return mono_w32file_copy (mono_string_chars (path), mono_string_chars (dest), overwrite, error);
366 }
367
368 MonoBoolean
369 ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
370 {
371         gboolean ret;
372         
373         *error=ERROR_SUCCESS;
374         
375         ret=mono_w32file_delete (mono_string_chars (path));
376         if(ret==FALSE) {
377                 *error=mono_w32error_get_last ();
378         }
379         
380         return(ret);
381 }
382
383 gint32 
384 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
385 {
386         gint32 ret;
387         *error=ERROR_SUCCESS;
388         
389         ret = mono_w32file_get_attributes (mono_string_chars (path));
390
391         /* 
392          * The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
393          * headers is wrong, hence this temporary workaround.
394          * See
395          * http://cygwin.com/ml/cygwin/2003-09/msg01771.html
396          */
397         if (ret==-1) {
398           /* if(ret==INVALID_FILE_ATTRIBUTES) { */
399                 *error=mono_w32error_get_last ();
400         }
401         return(ret);
402 }
403
404 MonoBoolean
405 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
406                                               gint32 *error)
407 {
408         gboolean ret;
409         *error=ERROR_SUCCESS;
410         
411         ret=mono_w32file_set_attributes (mono_string_chars (path),
412                 convert_attrs ((MonoFileAttributes)attrs));
413         if(ret==FALSE) {
414                 *error=mono_w32error_get_last ();
415         }
416         return(ret);
417 }
418
419 gint32
420 ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
421 {
422         gboolean ret;
423
424         *error=ERROR_SUCCESS;
425         
426         ret=mono_w32file_get_type (handle);
427         if(ret==FILE_TYPE_UNKNOWN) {
428                 /* Not necessarily an error, but the caller will have
429                  * to decide based on the error value.
430                  */
431                 *error=mono_w32error_get_last ();
432         }
433         
434         return(ret);
435 }
436
437 MonoBoolean
438 ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat, gint32 *error)
439 {
440         gboolean result;
441
442         *error=ERROR_SUCCESS;
443         
444         result = mono_w32file_get_attributes_ex (mono_string_chars (path), stat);
445
446         if (!result) {
447                 *error=mono_w32error_get_last ();
448                 memset (stat, 0, sizeof (MonoIOStat));
449         }
450
451         return result;
452 }
453
454 HANDLE 
455 ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
456                                  gint32 access_mode, gint32 share, gint32 options,
457                                  gint32 *error)
458 {
459         HANDLE ret;
460         int attributes, attrs;
461         gunichar2 *chars;
462
463         chars = mono_string_chars (filename);   
464         *error=ERROR_SUCCESS;
465
466         if (options != 0){
467                 if (options & FileOptions_Encrypted)
468                         attributes = FILE_ATTRIBUTE_ENCRYPTED;
469                 else
470                         attributes = FILE_ATTRIBUTE_NORMAL;
471                 if (options & FileOptions_DeleteOnClose)
472                         attributes |= FILE_FLAG_DELETE_ON_CLOSE;
473                 if (options & FileOptions_SequentialScan)
474                         attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
475                 if (options & FileOptions_RandomAccess)
476                         attributes |= FILE_FLAG_RANDOM_ACCESS;
477
478                 if (options & FileOptions_Temporary)
479                         attributes |= FILE_ATTRIBUTE_TEMPORARY;
480                 
481                 if (options & FileOptions_WriteThrough)
482                         attributes |= FILE_FLAG_WRITE_THROUGH;
483         } else
484                 attributes = FILE_ATTRIBUTE_NORMAL;
485
486         /* If we're opening a directory we need to set the extra flag
487          */
488         attrs = mono_w32file_get_attributes (chars);
489         if (attrs != INVALID_FILE_ATTRIBUTES) {
490                 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
491                         attributes |= FILE_FLAG_BACKUP_SEMANTICS;
492                 }
493         }
494         
495         ret=mono_w32file_create (chars, convert_access ((MonoFileAccess)access_mode), convert_share ((MonoFileShare)share), convert_mode ((MonoFileMode)mode), attributes);
496         if(ret==INVALID_HANDLE_VALUE) {
497                 *error=mono_w32error_get_last ();
498         } 
499         
500         return(ret);
501 }
502
503 MonoBoolean
504 ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
505 {
506         gboolean ret;
507         *error=ERROR_SUCCESS;
508         
509         ret=mono_w32file_close (handle);
510         if(ret==FALSE) {
511                 *error=mono_w32error_get_last ();
512         }
513         return(ret);
514 }
515
516 gint32 
517 ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
518                                  gint32 dest_offset, gint32 count,
519                                  gint32 *error)
520 {
521         guchar *buffer;
522         gboolean result;
523         guint32 n;
524
525         *error=ERROR_SUCCESS;
526
527         MONO_CHECK_ARG_NULL (dest, 0);
528
529         if (dest_offset > mono_array_length (dest) - count) {
530                 mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
531                 return 0;
532         }
533
534         buffer = mono_array_addr (dest, guchar, dest_offset);
535
536         result = mono_w32file_read (handle, buffer, count, &n);
537
538         if (!result) {
539                 *error=mono_w32error_get_last ();
540                 return -1;
541         }
542
543         return (gint32)n;
544 }
545
546 gint32 
547 ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
548                                   gint32 src_offset, gint32 count,
549                                   gint32 *error)
550 {
551         guchar *buffer;
552         gboolean result;
553         guint32 n;
554
555         *error=ERROR_SUCCESS;
556
557         MONO_CHECK_ARG_NULL (src, 0);
558         
559         if (src_offset > mono_array_length (src) - count) {
560                 mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
561                 return 0;
562         }
563         
564         buffer = mono_array_addr (src, guchar, src_offset);
565         result = mono_w32file_write (handle, buffer, count, &n);
566
567         if (!result) {
568                 *error=mono_w32error_get_last ();
569                 return -1;
570         }
571
572         return (gint32)n;
573 }
574
575 gint64 
576 ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
577                                  gint32 *error)
578 {
579         gint32 offset_hi;
580
581         *error=ERROR_SUCCESS;
582         
583         offset_hi = offset >> 32;
584         offset = mono_w32file_seek (handle, (gint32) (offset & 0xFFFFFFFF), &offset_hi,
585                                  convert_seekorigin ((MonoSeekOrigin)origin));
586
587         if(offset==INVALID_SET_FILE_POINTER) {
588                 *error=mono_w32error_get_last ();
589         }
590
591         return offset | ((gint64)offset_hi << 32);
592 }
593
594 MonoBoolean
595 ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
596 {
597         gboolean ret;
598
599         *error=ERROR_SUCCESS;
600         
601         ret=mono_w32file_flush (handle);
602         if(ret==FALSE) {
603                 *error=mono_w32error_get_last ();
604         }
605         
606         return(ret);
607 }
608
609 gint64
610 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
611 {
612         *error=ERROR_SUCCESS;
613         return mono_w32file_get_file_size (handle, error);
614 }
615
616 /* FIXME make gc suspendable */
617 MonoBoolean
618 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
619                                       gint32 *error)
620 {
621         gint64 offset, offset_set;
622         gint32 offset_hi;
623         gint32 length_hi;
624         gboolean result;
625
626         *error=ERROR_SUCCESS;
627         
628         /* save file pointer */
629
630         offset_hi = 0;
631         offset = mono_w32file_seek (handle, 0, &offset_hi, FILE_CURRENT);
632         if(offset==INVALID_SET_FILE_POINTER) {
633                 *error=mono_w32error_get_last ();
634                 return(FALSE);
635         }
636
637         /* extend or truncate */
638
639         length_hi = length >> 32;
640         offset_set=mono_w32file_seek (handle, length & 0xFFFFFFFF, &length_hi,
641                                    FILE_BEGIN);
642         if(offset_set==INVALID_SET_FILE_POINTER) {
643                 *error=mono_w32error_get_last ();
644                 return(FALSE);
645         }
646
647         result = mono_w32file_truncate (handle);
648         if(result==FALSE) {
649                 *error=mono_w32error_get_last ();
650                 return(FALSE);
651         }
652
653         /* restore file pointer */
654
655         offset_set=mono_w32file_seek (handle, offset & 0xFFFFFFFF, &offset_hi,
656                                    FILE_BEGIN);
657         if(offset_set==INVALID_SET_FILE_POINTER) {
658                 *error=mono_w32error_get_last ();
659                 return(FALSE);
660         }
661
662         return result;
663 }
664
665 MonoBoolean
666 ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
667                                         gint64 last_access_time,
668                                         gint64 last_write_time, gint32 *error)
669 {
670         gboolean ret;
671         const FILETIME *creation_filetime;
672         const FILETIME *access_filetime;
673         const FILETIME *write_filetime;
674
675         *error=ERROR_SUCCESS;
676         
677         if (creation_time < 0)
678                 creation_filetime = NULL;
679         else
680                 creation_filetime = (FILETIME *)&creation_time;
681
682         if (last_access_time < 0)
683                 access_filetime = NULL;
684         else
685                 access_filetime = (FILETIME *)&last_access_time;
686
687         if (last_write_time < 0)
688                 write_filetime = NULL;
689         else
690                 write_filetime = (FILETIME *)&last_write_time;
691
692         ret=mono_w32file_set_times (handle, creation_filetime, access_filetime, write_filetime);
693         if(ret==FALSE) {
694                 *error=mono_w32error_get_last ();
695         }
696
697         return(ret);
698 }
699
700 HANDLE 
701 ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
702 {
703         return mono_w32file_get_console_output ();
704 }
705
706 HANDLE 
707 ves_icall_System_IO_MonoIO_get_ConsoleInput ()
708 {
709         return mono_w32file_get_console_input ();
710 }
711
712 HANDLE 
713 ves_icall_System_IO_MonoIO_get_ConsoleError ()
714 {
715         return mono_w32file_get_console_error ();
716 }
717
718 MonoBoolean
719 ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle, HANDLE *write_handle, gint32 *error)
720 {
721         gboolean ret;
722
723         ret=mono_w32file_create_pipe (read_handle, write_handle, 0);
724
725         if(ret==FALSE) {
726                 *error = mono_w32error_get_last ();
727                 /* FIXME: throw an exception? */
728                 return(FALSE);
729         }
730         
731         return(TRUE);
732 }
733
734 MonoBoolean
735 ves_icall_System_IO_MonoIO_DuplicateHandle (HANDLE source_process_handle, HANDLE source_handle,
736                 HANDLE target_process_handle, HANDLE *target_handle, gint32 access, gint32 inherit, gint32 options, gint32 *error)
737 {
738 #ifndef HOST_WIN32
739         *target_handle = mono_w32handle_duplicate (source_handle);
740 #else
741         gboolean ret;
742
743         MONO_ENTER_GC_SAFE;
744         ret=DuplicateHandle (source_process_handle, source_handle, target_process_handle, target_handle, access, inherit, options);
745         MONO_EXIT_GC_SAFE;
746
747         if (!ret) {
748                 *error = mono_w32error_get_last ();
749                 /* FIXME: throw an exception? */
750                 return(FALSE);
751         }
752 #endif
753
754         return(TRUE);
755 }
756
757 #ifndef HOST_WIN32
758 gunichar2 
759 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
760 {
761         return (gunichar2) '/'; /* forward slash */
762 }
763
764 gunichar2 
765 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
766 {
767         return (gunichar2) '/'; /* forward slash */
768 }
769
770 gunichar2 
771 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
772 {
773         if (IS_PORTABILITY_SET)
774                 return (gunichar2) '\\';        /* backslash */
775         else
776                 return (gunichar2) '/'; /* forward slash */
777 }
778
779 gunichar2 
780 ves_icall_System_IO_MonoIO_get_PathSeparator ()
781 {
782         return (gunichar2) ':'; /* colon */
783 }
784 #endif /* !HOST_WIN32 */
785
786 static const gunichar2
787 invalid_path_chars [] = {
788 #if defined (TARGET_WIN32)
789         0x0022,                         /* double quote, which seems allowed in MS.NET but should be rejected */
790         0x003c,                         /* less than */
791         0x003e,                         /* greater than */
792         0x007c,                         /* pipe */
793         0x0008,
794         0x0010,
795         0x0011,
796         0x0012,
797         0x0014,
798         0x0015,
799         0x0016,
800         0x0017,
801         0x0018,
802         0x0019,
803 #endif
804         0x0000                          /* null */
805 };
806
807 MonoArray *
808 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
809 {
810         MonoError error;
811         MonoArray *chars;
812         MonoDomain *domain;
813         int i, n;
814
815         domain = mono_domain_get ();
816         n = sizeof (invalid_path_chars) / sizeof (gunichar2);
817         chars = mono_array_new_checked (domain, mono_defaults.char_class, n, &error);
818         if (mono_error_set_pending_exception (&error))
819                 return NULL;
820
821         for (i = 0; i < n; ++ i)
822                 mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
823         
824         return chars;
825 }
826
827 void ves_icall_System_IO_MonoIO_Lock (HANDLE handle, gint64 position,
828                                       gint64 length, gint32 *error)
829 {
830         *error=ERROR_SUCCESS;
831         mono_w32file_lock (handle, position, length, error);
832 }
833
834 void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
835                                         gint64 length, gint32 *error)
836 {
837         *error=ERROR_SUCCESS;
838         mono_w32file_unlock (handle, position, length, error);
839 }
840
841 //Support for io-layer free mmap'd files.
842
843 #if defined (TARGET_IOS) || defined (TARGET_ANDROID)
844
845 gint64
846 mono_filesize_from_path (MonoString *string)
847 {
848         MonoError error;
849         struct stat buf;
850         gint64 res;
851         char *path = mono_string_to_utf8_checked (string, &error);
852         mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
853
854         gint stat_res;
855         MONO_ENTER_GC_SAFE;
856         stat_res = stat (path, &buf);
857         MONO_EXIT_GC_SAFE;
858         if (stat_res == -1)
859                 res = -1;
860         else
861                 res = (gint64)buf.st_size;
862
863         g_free (path);
864
865         return res;
866 }
867
868 gint64
869 mono_filesize_from_fd (int fd)
870 {
871         struct stat buf;
872         int res;
873
874         MONO_ENTER_GC_SAFE;
875         res = fstat (fd, &buf);
876         MONO_EXIT_GC_SAFE;
877         
878         if (res == -1)
879                 return (gint64)-1;
880
881         return (gint64)buf.st_size;
882 }
883
884 #endif
885
886 #ifndef HOST_WIN32
887 void mono_w32handle_dump (void);
888
889 void ves_icall_System_IO_MonoIO_DumpHandles (void)
890 {
891         mono_w32handle_dump ();
892 }
893 #endif /* !HOST_WIN32 */