copying the latest Sys.Web.Services from trunk.
[mono.git] / mono / metadata / file-io.c
1 /*
2  * file-io.c: File IO internal calls
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <signal.h>
15 #include <unistd.h>
16
17 #include <mono/metadata/object.h>
18 #include <mono/io-layer/io-layer.h>
19 #include <mono/metadata/file-io.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/appdomain.h>
22 #include <mono/metadata/marshal.h>
23
24 #undef DEBUG
25
26 /* conversion functions */
27
28 static guint32 convert_mode(MonoFileMode mono_mode)
29 {
30         guint32 mode;
31
32         switch(mono_mode) {
33         case FileMode_CreateNew:
34                 mode=CREATE_NEW;
35                 break;
36         case FileMode_Create:
37                 mode=CREATE_ALWAYS;
38                 break;
39         case FileMode_Open:
40                 mode=OPEN_EXISTING;
41                 break;
42         case FileMode_OpenOrCreate:
43                 mode=OPEN_ALWAYS;
44                 break;
45         case FileMode_Truncate:
46                 mode=TRUNCATE_EXISTING;
47                 break;
48         case FileMode_Append:
49                 mode=OPEN_ALWAYS;
50                 break;
51         default:
52                 g_warning("System.IO.FileMode has unknown value 0x%x",
53                           mono_mode);
54                 /* Safe fallback */
55                 mode=OPEN_EXISTING;
56         }
57         
58         return(mode);
59 }
60
61 static guint32 convert_access(MonoFileAccess mono_access)
62 {
63         guint32 access;
64         
65         switch(mono_access) {
66         case FileAccess_Read:
67                 access=GENERIC_READ;
68                 break;
69         case FileAccess_Write:
70                 access=GENERIC_WRITE;
71                 break;
72         case FileAccess_ReadWrite:
73                 access=GENERIC_READ|GENERIC_WRITE;
74                 break;
75         default:
76                 g_warning("System.IO.FileAccess has unknown value 0x%x",
77                           mono_access);
78                 /* Safe fallback */
79                 access=GENERIC_READ;
80         }
81         
82         return(access);
83 }
84
85 static guint32 convert_share(MonoFileShare mono_share)
86 {
87         guint32 share;
88         
89         switch(mono_share) {
90         case FileShare_None:
91                 share=0;
92                 break;
93         case FileShare_Read:
94                 share=FILE_SHARE_READ;
95                 break;
96         case FileShare_Write:
97                 share=FILE_SHARE_WRITE;
98                 break;
99         case FileShare_ReadWrite:
100                 share=FILE_SHARE_READ|FILE_SHARE_WRITE;
101                 break;
102         default:
103                 g_warning("System.IO.FileShare has unknown value 0x%x",
104                           mono_share);
105                 /* Safe fallback */
106                 share=0;
107         }
108         
109         return(share);
110 }
111
112 #if 0
113 static guint32 convert_stdhandle(guint32 fd)
114 {
115         guint32 stdhandle;
116         
117         switch(fd) {
118         case 0:
119                 stdhandle=STD_INPUT_HANDLE;
120                 break;
121         case 1:
122                 stdhandle=STD_OUTPUT_HANDLE;
123                 break;
124         case 2:
125                 stdhandle=STD_ERROR_HANDLE;
126                 break;
127         default:
128                 g_warning("unknown standard file descriptor %d", fd);
129                 stdhandle=STD_INPUT_HANDLE;
130         }
131         
132         return(stdhandle);
133 }
134 #endif
135
136 static guint32 convert_seekorigin(MonoSeekOrigin origin)
137 {
138         guint32 w32origin;
139         
140         switch(origin) {
141         case SeekOrigin_Begin:
142                 w32origin=FILE_BEGIN;
143                 break;
144         case SeekOrigin_Current:
145                 w32origin=FILE_CURRENT;
146                 break;
147         case SeekOrigin_End:
148                 w32origin=FILE_END;
149                 break;
150         default:
151                 g_warning("System.IO.SeekOrigin has unknown value 0x%x",
152                           origin);
153                 /* Safe fallback */
154                 w32origin=FILE_CURRENT;
155         }
156         
157         return(w32origin);
158 }
159
160 static gint64 convert_filetime (const FILETIME *filetime)
161 {
162         guint64 ticks = filetime->dwHighDateTime;
163         ticks <<= 32;
164         ticks += filetime->dwLowDateTime;
165         return (gint64)ticks;
166 }
167
168 static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
169 {
170         int len;
171         
172         stat->attributes = data->dwFileAttributes;
173         stat->creation_time = convert_filetime (&data->ftCreationTime);
174         stat->last_access_time = convert_filetime (&data->ftLastAccessTime);
175         stat->last_write_time = convert_filetime (&data->ftLastWriteTime);
176         stat->length = ((gint64)data->nFileSizeHigh << 32) | data->nFileSizeLow;
177
178         len = 0;
179         while (name [len])
180                 ++ len;
181
182         stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
183 }
184
185 /* Managed file attributes have nearly but not quite the same values
186  * as the w32 equivalents.
187  */
188 static guint32 convert_attrs(MonoFileAttributes attrs)
189 {
190         if(attrs & FileAttributes_Encrypted) {
191                 attrs |= FILE_ATTRIBUTE_ENCRYPTED;
192         }
193         
194         return(attrs);
195 }
196
197 /* System.IO.MonoIO internal calls */
198
199 MonoBoolean
200 ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
201 {
202         gboolean ret;
203         
204         MONO_ARCH_SAVE_REGS;
205
206         *error=ERROR_SUCCESS;
207         
208         ret=CreateDirectory (mono_string_chars (path), NULL);
209         if(ret==FALSE) {
210                 *error=GetLastError ();
211         }
212         
213         return(ret);
214 }
215
216 MonoBoolean
217 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
218 {
219         gboolean ret;
220         
221         MONO_ARCH_SAVE_REGS;
222
223         *error=ERROR_SUCCESS;
224         
225         ret=RemoveDirectory (mono_string_chars (path));
226         if(ret==FALSE) {
227                 *error=GetLastError ();
228         }
229         
230         return(ret);
231 }
232
233 HANDLE 
234 ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat,
235                                           gint32 *error)
236 {
237         WIN32_FIND_DATA data;
238         HANDLE result;
239         gboolean r = TRUE;
240
241         MONO_ARCH_SAVE_REGS;
242
243         *error=ERROR_SUCCESS;
244
245         result = FindFirstFile (mono_string_chars (path), &data);
246
247         /* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
248         while (result != INVALID_HANDLE_VALUE && r) {
249                 if ((data.cFileName [0] == '.' && data.cFileName [1] == 0) ||
250                     (data.cFileName [0] == '.' && data.cFileName [1] == '.' && data.cFileName [2] == 0)) {
251                         r = FindNextFile (result, &data);
252                 } else {
253                         convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
254                                                            &data.cFileName [0], stat);
255                         break;
256                 } 
257         }
258         
259         if (result == INVALID_HANDLE_VALUE) {
260                 *error=GetLastError ();
261         }
262         
263         if (r == FALSE) {
264                 /* No more files were found, after we discarded . and .. */
265                 FindClose(result);
266                 result = INVALID_HANDLE_VALUE;
267                 *error = ERROR_NO_MORE_FILES;
268         }
269
270         return result;
271 }
272
273 MonoBoolean
274 ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat,
275                                          gint32 *error)
276 {
277         WIN32_FIND_DATA data;
278         gboolean result;
279
280         MONO_ARCH_SAVE_REGS;
281
282         *error=ERROR_SUCCESS;
283         
284         result = FindNextFile (find, &data);
285         while (result != FALSE) {
286                 if ((data.cFileName [0] == '.' && data.cFileName [1] == 0) ||
287                     (data.cFileName [0] == '.' && data.cFileName [1] == '.' && data.cFileName [2] == 0)) {
288                         result = FindNextFile (find, &data);
289                 } else {
290                         convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
291                                                            &data.cFileName [0], stat);
292                         break;
293                 } 
294         }
295         
296         if (result == FALSE) {
297                 *error=GetLastError ();
298         }
299
300         return result;
301 }
302
303 MonoBoolean
304 ves_icall_System_IO_MonoIO_FindClose (HANDLE find, gint32 *error)
305 {
306         gboolean ret;
307         
308         MONO_ARCH_SAVE_REGS;
309
310         *error=ERROR_SUCCESS;
311         
312         ret=FindClose (find);
313         if(ret==FALSE) {
314                 *error=GetLastError ();
315         }
316         
317         return(ret);
318 }
319
320 MonoString *
321 ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
322 {
323         MonoString *result;
324         gunichar2 *buf;
325         int len;
326
327         MONO_ARCH_SAVE_REGS;
328
329         len = MAX_PATH + 1;
330         buf = g_new (gunichar2, len);
331         
332         *error=ERROR_SUCCESS;
333         result = NULL;
334
335         if (GetCurrentDirectory (len, buf) > 0) {
336                 len = 0;
337                 while (buf [len])
338                         ++ len;
339
340                 result = mono_string_new_utf16 (mono_domain_get (), buf, len);
341         } else {
342                 *error=GetLastError ();
343         }
344
345         g_free (buf);
346         return result;
347 }
348
349 MonoBoolean
350 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
351                                                 gint32 *error)
352 {
353         gboolean ret;
354         
355         MONO_ARCH_SAVE_REGS;
356
357         *error=ERROR_SUCCESS;
358         
359         ret=SetCurrentDirectory (mono_string_chars (path));
360         if(ret==FALSE) {
361                 *error=GetLastError ();
362         }
363         
364         return(ret);
365 }
366
367 MonoBoolean
368 ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
369                                      gint32 *error)
370 {
371         gboolean ret;
372         
373         MONO_ARCH_SAVE_REGS;
374
375         *error=ERROR_SUCCESS;
376         
377         ret=MoveFile (mono_string_chars (path), mono_string_chars (dest));
378         if(ret==FALSE) {
379                 *error=GetLastError ();
380         }
381         
382         return(ret);
383 }
384
385 MonoBoolean
386 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
387                                      MonoBoolean overwrite, gint32 *error)
388 {
389         gboolean ret;
390         
391         MONO_ARCH_SAVE_REGS;
392
393         *error=ERROR_SUCCESS;
394         
395         ret=CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
396         if(ret==FALSE) {
397                 *error=GetLastError ();
398         }
399         
400         return(ret);
401 }
402
403 MonoBoolean
404 ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
405 {
406         gboolean ret;
407         
408         MONO_ARCH_SAVE_REGS;
409
410         *error=ERROR_SUCCESS;
411         
412         ret=DeleteFile (mono_string_chars (path));
413         if(ret==FALSE) {
414                 *error=GetLastError ();
415         }
416         
417         return(ret);
418 }
419
420 gint32 
421 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
422 {
423         gint32 ret;
424         
425         MONO_ARCH_SAVE_REGS;
426
427         *error=ERROR_SUCCESS;
428         
429         ret=GetFileAttributes (mono_string_chars (path));
430
431         /* 
432          * The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
433          * headers is wrong, hence this temporary workaround.
434          * See
435          * http://cygwin.com/ml/cygwin/2003-09/msg01771.html
436          */
437         if (ret==-1) {
438           /* if(ret==INVALID_FILE_ATTRIBUTES) { */
439                 *error=GetLastError ();
440         }
441         
442         return(ret);
443 }
444
445 MonoBoolean
446 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
447                                               gint32 *error)
448 {
449         gboolean ret;
450         
451         MONO_ARCH_SAVE_REGS;
452
453         *error=ERROR_SUCCESS;
454         
455         ret=SetFileAttributes (mono_string_chars (path),
456                                convert_attrs (attrs));
457         if(ret==FALSE) {
458                 *error=GetLastError ();
459         }
460         
461         return(ret);
462 }
463
464 gint32
465 ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
466 {
467         gboolean ret;
468         
469         MONO_ARCH_SAVE_REGS;
470
471         *error=ERROR_SUCCESS;
472         
473         ret=GetFileType (handle);
474         if(ret==FILE_TYPE_UNKNOWN) {
475                 /* Not necessarily an error, but the caller will have
476                  * to decide based on the error value.
477                  */
478                 *error=GetLastError ();
479         }
480         
481         return(ret);
482 }
483
484 MonoBoolean
485 ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
486                                         gint32 *error)
487 {
488         gboolean result;
489         WIN32_FILE_ATTRIBUTE_DATA data;
490
491         MONO_ARCH_SAVE_REGS;
492
493         *error=ERROR_SUCCESS;
494         
495         result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
496
497         if (result) {
498                 convert_win32_file_attribute_data (&data,
499                                                    mono_string_chars (path),
500                                                    stat);
501         } else {
502                 *error=GetLastError ();
503         }
504
505         return result;
506 }
507
508 HANDLE 
509 ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
510                                  gint32 access_mode, gint32 share,
511                                  MonoBoolean async, gint32 *error)
512 {
513         HANDLE ret;
514         
515         MONO_ARCH_SAVE_REGS;
516
517         *error=ERROR_SUCCESS;
518         
519         ret=CreateFile (mono_string_chars (filename),
520                         convert_access (access_mode), convert_share (share),
521                         NULL, convert_mode (mode),
522                         FILE_ATTRIBUTE_NORMAL | ((async) ? FILE_FLAG_OVERLAPPED : 0),
523                         NULL);
524         if(ret==INVALID_HANDLE_VALUE) {
525                 *error=GetLastError ();
526         }
527         
528         return(ret);
529 }
530
531 MonoBoolean
532 ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
533 {
534         gboolean ret;
535         
536         MONO_ARCH_SAVE_REGS;
537
538         *error=ERROR_SUCCESS;
539         
540         ret=CloseHandle (handle);
541         if(ret==FALSE) {
542                 *error=GetLastError ();
543         }
544         
545         return(ret);
546 }
547
548 gint32 
549 ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
550                                  gint32 dest_offset, gint32 count,
551                                  gint32 *error)
552 {
553         guchar *buffer;
554         gboolean result;
555         guint32 n;
556
557         MONO_ARCH_SAVE_REGS;
558
559         *error=ERROR_SUCCESS;
560         
561         if (dest_offset + count > mono_array_length (dest))
562                 return 0;
563
564         buffer = mono_array_addr (dest, guchar, dest_offset);
565         result = ReadFile (handle, buffer, count, &n, NULL);
566
567         if (!result) {
568                 *error=GetLastError ();
569                 return -1;
570         }
571
572         return (gint32)n;
573 }
574
575 gint32 
576 ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
577                                   gint32 src_offset, gint32 count,
578                                   gint32 *error)
579 {
580         guchar *buffer;
581         gboolean result;
582         guint32 n;
583
584         MONO_ARCH_SAVE_REGS;
585
586         *error=ERROR_SUCCESS;
587         
588         if (src_offset + count > mono_array_length (src))
589                 return 0;
590         
591         buffer = mono_array_addr (src, guchar, src_offset);
592         result = WriteFile (handle, buffer, count, &n, NULL);
593
594         if (!result) {
595                 *error=GetLastError ();
596                 return -1;
597         }
598
599         return (gint32)n;
600 }
601
602 gint64 
603 ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
604                                  gint32 *error)
605 {
606         guint32 offset_hi;
607
608         MONO_ARCH_SAVE_REGS;
609
610         *error=ERROR_SUCCESS;
611         
612         offset_hi = offset >> 32;
613         offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
614                                  convert_seekorigin (origin));
615
616         if(offset==INVALID_SET_FILE_POINTER) {
617                 *error=GetLastError ();
618         }
619         
620         return offset | ((gint64)offset_hi << 32);
621 }
622
623 MonoBoolean
624 ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
625 {
626         gboolean ret;
627         
628         MONO_ARCH_SAVE_REGS;
629
630         *error=ERROR_SUCCESS;
631         
632         ret=FlushFileBuffers (handle);
633         if(ret==FALSE) {
634                 *error=GetLastError ();
635         }
636         
637         return(ret);
638 }
639
640 gint64 
641 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
642 {
643         gint64 length;
644         guint32 length_hi;
645
646         MONO_ARCH_SAVE_REGS;
647
648         *error=ERROR_SUCCESS;
649         
650         length = GetFileSize (handle, &length_hi);
651         if(length==INVALID_FILE_SIZE) {
652                 *error=GetLastError ();
653         }
654         
655         return length | ((gint64)length_hi << 32);
656 }
657
658 MonoBoolean
659 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
660                                       gint32 *error)
661 {
662         gint64 offset, offset_set;
663         gint32 offset_hi;
664         gint32 length_hi;
665         gboolean result;
666
667         MONO_ARCH_SAVE_REGS;
668
669         *error=ERROR_SUCCESS;
670         
671         /* save file pointer */
672
673         offset_hi = 0;
674         offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
675         if(offset==INVALID_SET_FILE_POINTER) {
676                 *error=GetLastError ();
677                 return(FALSE);
678         }
679
680         /* extend or truncate */
681
682         length_hi = length >> 32;
683         offset_set=SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi,
684                                    FILE_BEGIN);
685         if(offset_set==INVALID_SET_FILE_POINTER) {
686                 *error=GetLastError ();
687                 return(FALSE);
688         }
689
690         result = SetEndOfFile (handle);
691         if(result==FALSE) {
692                 *error=GetLastError ();
693                 return(FALSE);
694         }
695
696         /* restore file pointer */
697
698         offset_set=SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
699                                    FILE_BEGIN);
700         if(offset_set==INVALID_SET_FILE_POINTER) {
701                 *error=GetLastError ();
702                 return(FALSE);
703         }
704
705         return result;
706 }
707
708 MonoBoolean
709 ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
710                                         gint64 last_access_time,
711                                         gint64 last_write_time, gint32 *error)
712 {
713         gboolean ret;
714         const FILETIME *creation_filetime;
715         const FILETIME *last_access_filetime;
716         const FILETIME *last_write_filetime;
717
718         MONO_ARCH_SAVE_REGS;
719
720         *error=ERROR_SUCCESS;
721         
722         if (creation_time < 0)
723                 creation_filetime = NULL;
724         else
725                 creation_filetime = (FILETIME *)&creation_time;
726
727         if (last_access_time < 0)
728                 last_access_filetime = NULL;
729         else
730                 last_access_filetime = (FILETIME *)&last_access_time;
731
732         if (last_write_time < 0)
733                 last_write_filetime = NULL;
734         else
735                 last_write_filetime = (FILETIME *)&last_write_time;
736
737         ret=SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
738         if(ret==FALSE) {
739                 *error=GetLastError ();
740         }
741         
742         return(ret);
743 }
744
745 HANDLE 
746 ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
747 {
748         MONO_ARCH_SAVE_REGS;
749
750         return GetStdHandle (STD_OUTPUT_HANDLE);
751 }
752
753 HANDLE 
754 ves_icall_System_IO_MonoIO_get_ConsoleInput ()
755 {
756         MONO_ARCH_SAVE_REGS;
757
758         return GetStdHandle (STD_INPUT_HANDLE);
759 }
760
761 HANDLE 
762 ves_icall_System_IO_MonoIO_get_ConsoleError ()
763 {
764         MONO_ARCH_SAVE_REGS;
765
766         return GetStdHandle (STD_ERROR_HANDLE);
767 }
768
769 MonoBoolean
770 ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
771                                        HANDLE *write_handle)
772 {
773         SECURITY_ATTRIBUTES attr;
774         gboolean ret;
775         
776         MONO_ARCH_SAVE_REGS;
777
778         attr.nLength=sizeof(SECURITY_ATTRIBUTES);
779         attr.bInheritHandle=TRUE;
780         attr.lpSecurityDescriptor=NULL;
781         
782         ret=CreatePipe (read_handle, write_handle, &attr, 0);
783         if(ret==FALSE) {
784                 /* FIXME: throw an exception? */
785                 return(FALSE);
786         }
787         
788         return(TRUE);
789 }
790
791 gunichar2 
792 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
793 {
794 #if defined (PLATFORM_WIN32)
795         return (gunichar2) ':'; /* colon */
796 #else
797         return (gunichar2) '/'; /* forward slash */
798 #endif
799 }
800
801 gunichar2 
802 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
803 {
804 #if defined (PLATFORM_WIN32)
805         return (gunichar2) '\\';        /* backslash */
806 #else
807         return (gunichar2) '/'; /* forward slash */
808 #endif
809 }
810
811 gunichar2 
812 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
813 {
814 #if defined (PLATFORM_WIN32)
815         return (gunichar2) '/'; /* forward slash */
816 #else
817         return (gunichar2) '/'; /* slash, same as DirectorySeparatorChar */
818 #endif
819 }
820
821 gunichar2 
822 ves_icall_System_IO_MonoIO_get_PathSeparator ()
823 {
824 #if defined (PLATFORM_WIN32)
825         return (gunichar2) ';'; /* semicolon */
826 #else
827         return (gunichar2) ':'; /* colon */
828 #endif
829 }
830
831 static const gunichar2
832 invalid_path_chars [] = {
833 #if defined (PLATFORM_WIN32)
834         0x0022,                         /* double quote, which seems allowed in MS.NET but should be rejected */
835         0x003c,                         /* less than */
836         0x003e,                         /* greater than */
837         0x007c,                         /* pipe */
838         0x0008,
839         0x0010,
840         0x0011,
841         0x0012,
842         0x0014,
843         0x0015,
844         0x0016,
845         0x0017,
846         0x0018,
847         0x0019,
848 #endif
849         0x0000                          /* null */
850 };
851
852 MonoArray *
853 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
854 {
855         MonoArray *chars;
856         MonoDomain *domain;
857         int i, n;
858
859         MONO_ARCH_SAVE_REGS;
860
861         domain = mono_domain_get ();
862         n = sizeof (invalid_path_chars) / sizeof (gunichar2);
863         chars = mono_array_new (domain, mono_defaults.char_class, n);
864
865         for (i = 0; i < n; ++ i)
866                 mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
867         
868         return chars;
869 }
870
871 gint32
872 ves_icall_System_IO_MonoIO_GetTempPath (MonoString **mono_name)
873 {
874         gunichar2 *name;
875         int ret;
876
877         name=g_new0 (gunichar2, 256);
878         
879         ret=GetTempPath (256, name);
880         if(ret>255) {
881                 /* Buffer was too short. Try again... */
882                 g_free (name);
883                 name=g_new0 (gunichar2, ret+2); /* include the terminator */
884                 ret=GetTempPath (ret, name);
885         }
886         
887         if(ret>0) {
888 #ifdef DEBUG
889                 g_message (G_GNUC_PRETTY_FUNCTION
890                            ": Temp path is [%s] (len %d)", name, ret);
891 #endif
892
893                 *mono_name=mono_string_new_utf16 (mono_domain_get (), name,
894                                                   ret);
895         }
896
897         g_free (name);
898         
899         return(ret);
900 }
901
902 void ves_icall_System_IO_MonoIO_Lock (HANDLE handle, gint64 position,
903                                       gint64 length, gint32 *error)
904 {
905         gboolean ret;
906         
907         *error=ERROR_SUCCESS;
908         
909         ret=LockFile (handle, position & 0xFFFFFFFF, position >> 32,
910                       length & 0xFFFFFFFF, length >> 32);
911         if (ret == FALSE) {
912                 *error = GetLastError ();
913         }
914 }
915
916 void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
917                                         gint64 length, gint32 *error)
918 {
919         gboolean ret;
920         
921         *error=ERROR_SUCCESS;
922         
923         ret=UnlockFile (handle, position & 0xFFFFFFFF, position >> 32,
924                         length & 0xFFFFFFFF, length >> 32);
925         if (ret == FALSE) {
926                 *error = GetLastError ();
927         }
928 }
929