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