Added System.Buffer support. Moved file io calls to FileStream.
[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
13 #include <mono/metadata/object.h>
14 #include <mono/io-layer/io-layer.h>
15 #include <mono/metadata/file-io.h>
16 #include <mono/metadata/exception.h>
17 #include <mono/metadata/appdomain.h>
18
19 #define DEBUG
20
21 static guint32 convert_mode(MonoFileMode mono_mode)
22 {
23         guint32 mode;
24
25         switch(mono_mode) {
26         case FileMode_CreateNew:
27                 mode=CREATE_NEW;
28                 break;
29         case FileMode_Create:
30                 mode=CREATE_ALWAYS;
31                 break;
32         case FileMode_Open:
33                 mode=OPEN_EXISTING;
34                 break;
35         case FileMode_OpenOrCreate:
36                 mode=OPEN_ALWAYS;
37                 break;
38         case FileMode_Truncate:
39                 mode=TRUNCATE_EXISTING;
40                 break;
41         case FileMode_Append:
42                 mode=OPEN_ALWAYS;
43                 break;
44         default:
45                 g_warning("System.IO.FileMode has unknown value 0x%x",
46                           mono_mode);
47                 /* Safe fallback */
48                 mode=OPEN_EXISTING;
49         }
50         
51         return(mode);
52 }
53
54 static guint32 convert_access(MonoFileAccess mono_access)
55 {
56         guint32 access;
57         
58         switch(mono_access) {
59         case FileAccess_Read:
60                 access=GENERIC_READ;
61                 break;
62         case FileAccess_Write:
63                 access=GENERIC_WRITE;
64                 break;
65         case FileAccess_ReadWrite:
66                 access=GENERIC_READ|GENERIC_WRITE;
67                 break;
68         default:
69                 g_warning("System.IO.FileAccess has unknown value 0x%x",
70                           mono_access);
71                 /* Safe fallback */
72                 access=GENERIC_READ;
73         }
74         
75         return(access);
76 }
77
78 static guint32 convert_share(MonoFileShare mono_share)
79 {
80         guint32 share;
81         
82         switch(mono_share) {
83         case FileShare_None:
84                 share=0;
85                 break;
86         case FileShare_Read:
87                 share=FILE_SHARE_READ;
88                 break;
89         case FileShare_Write:
90                 share=FILE_SHARE_WRITE;
91                 break;
92         case FileShare_ReadWrite:
93                 share=FILE_SHARE_READ|FILE_SHARE_WRITE;
94                 break;
95         default:
96                 g_warning("System.IO.FileShare has unknown value 0x%x",
97                           mono_share);
98                 /* Safe fallback */
99                 share=0;
100         }
101         
102         return(share);
103 }
104
105 static guint32 convert_stdhandle(guint32 fd)
106 {
107         guint32 stdhandle;
108         
109         switch(fd) {
110         case 0:
111                 stdhandle=STD_INPUT_HANDLE;
112                 break;
113         case 1:
114                 stdhandle=STD_OUTPUT_HANDLE;
115                 break;
116         case 2:
117                 stdhandle=STD_ERROR_HANDLE;
118                 break;
119         default:
120                 g_warning("unknown standard file descriptor %d", fd);
121                 stdhandle=STD_INPUT_HANDLE;
122         }
123         
124         return(stdhandle);
125 }
126
127 static guint32 convert_seekorigin(MonoSeekOrigin origin)
128 {
129         guint32 w32origin;
130         
131         switch(origin) {
132         case SeekOrigin_Begin:
133                 w32origin=FILE_BEGIN;
134                 break;
135         case SeekOrigin_Current:
136                 w32origin=FILE_CURRENT;
137                 break;
138         case SeekOrigin_End:
139                 w32origin=FILE_END;
140                 break;
141         default:
142                 g_warning("System.IO.SeekOrigin has unknown value 0x%x",
143                           origin);
144                 /* Safe fallback */
145                 w32origin=FILE_CURRENT;
146         }
147         
148         return(w32origin);
149 }
150
151 /* fd must be one of stdin (value 0), stdout (1) or stderr (2).  These
152  * values must be hardcoded in corlib.
153  */
154 HANDLE ves_icall_System_PAL_OpSys_GetStdHandle(MonoObject *this,
155                                                gint32 fd)
156 {
157         HANDLE handle;
158
159         if(fd!=0 && fd!=1 && fd!=2) {
160                 mono_raise_exception(mono_get_exception_io("Invalid file descriptor"));
161         }
162         
163         handle=GetStdHandle(convert_stdhandle(fd));
164         
165         return(handle);
166 }
167
168 void ves_icall_System_PAL_OpSys_DeleteFile(MonoObject *this, MonoString *path)
169 {
170         char *filename;
171         
172         filename=mono_string_to_utf16(path);
173         
174         DeleteFile(filename);
175
176         g_free(filename);
177 }
178
179 gboolean ves_icall_System_PAL_OpSys_ExistsFile(MonoObject *this, MonoString *path)
180 {
181         return(FALSE);
182 }
183
184 gboolean ves_icall_System_PAL_OpSys_GetFileTime(HANDLE handle, gint64 *createtime, gint64 *lastaccess, gint64 *lastwrite)
185 {
186         gboolean ret;
187         FILETIME cr, ac, wr;
188         
189         if(handle == INVALID_HANDLE_VALUE) 
190                 mono_raise_exception(mono_get_exception_io("Invalid handle"));
191
192         ret=GetFileTime(handle, &cr, &ac, &wr);
193         if(ret==TRUE) {
194                 /* The FILETIME struct holds two unsigned 32 bit
195                  * values for the low and high bytes, but the .net
196                  * file time insists on being signed :(
197                  */
198                 *createtime=((gint64)cr.dwHighDateTime << 32) +
199                         cr.dwLowDateTime;
200                 *lastaccess=((gint64)ac.dwHighDateTime << 32) +
201                         ac.dwLowDateTime;
202                 *lastwrite=((gint64)wr.dwHighDateTime << 32) +
203                         wr.dwLowDateTime;
204         }
205         
206         return(ret);
207 }
208
209 gboolean ves_icall_System_PAL_OpSys_SetFileTime(HANDLE handle, gint64 createtime, gint64 lastaccess, gint64 lastwrite)
210 {
211         gboolean ret;
212         FILETIME cr, ac, wr;
213         
214         if(handle == INVALID_HANDLE_VALUE)
215                 mono_raise_exception(mono_get_exception_io("Invalid handle"));
216
217         cr.dwLowDateTime= createtime & 0xFFFFFFFF;
218         cr.dwHighDateTime= createtime >> 32;
219         
220         ac.dwLowDateTime= lastaccess & 0xFFFFFFFF;
221         ac.dwHighDateTime= lastaccess >> 32;
222         
223         wr.dwLowDateTime= lastwrite & 0xFFFFFFFF;
224         wr.dwHighDateTime= lastwrite >> 32;
225
226         ret=SetFileTime(handle, &cr, &ac, &wr);
227         
228         return(ret);
229 }
230
231 /* System.IO.FileStream */
232
233 HANDLE
234 ves_icall_System_IO_FileStream_FileOpen (MonoString *path, gint32 mode, gint32 access, gint32 share) {
235         HANDLE handle;
236         char *filename;
237         
238         filename=mono_string_to_utf16(path);
239         
240         handle=CreateFile(filename, convert_access(access),
241                           convert_share(share), NULL, convert_mode(mode),
242                           FILE_ATTRIBUTE_NORMAL, NULL);
243
244         g_free(filename);
245         
246         /* fixme: raise mor appropriate exceptions (errno) */
247         if(handle == INVALID_HANDLE_VALUE) {
248                 mono_raise_exception(mono_get_exception_io("Invalid handle"));
249         }
250
251         return(handle);
252 }
253
254 void 
255 ves_icall_System_IO_FileStream_FileClose (gpointer handle) {
256         if(handle == INVALID_HANDLE_VALUE) {
257                 mono_raise_exception(mono_get_exception_io("Invalid handle"));
258         }
259
260         CloseHandle(handle);
261 }
262
263 gint32 
264 ves_icall_System_IO_FileStream_FileRead (gpointer handle, MonoArray *dest, gint32 dest_offset, gint32 count) {
265         gboolean ret;
266         guint32 bytesread;
267         guchar *buf;
268         gint32 alen;
269
270         if(handle == INVALID_HANDLE_VALUE) {
271                 mono_raise_exception(mono_get_exception_io("Invalid handle"));
272         }
273
274         alen=mono_array_length(dest);
275         if(dest_offset+count>alen) {
276                 return(0);
277         }
278         
279         buf=mono_array_addr(dest, guchar, dest_offset);
280         
281         ret=ReadFile(handle, buf, count, &bytesread, NULL);
282         
283         return(bytesread);
284 }
285
286 gint32 
287 ves_icall_System_IO_FileStream_FileWrite (gpointer handle, MonoArray *src, gint32 src_offset, gint32 count) {
288         gboolean ret;
289         guint32 byteswritten;
290         guchar *buf;
291         gint32 alen;
292         
293         if(handle == INVALID_HANDLE_VALUE) {
294                 mono_raise_exception(mono_get_exception_io("Invalid handle"));
295         }
296
297         alen=mono_array_length(src);
298         if(src_offset+count>alen) {
299                 return(0);
300         }
301         
302         buf=mono_array_addr(src, guchar, src_offset);
303         
304         ret=WriteFile(handle, buf, count, &byteswritten, NULL);
305         
306         return(byteswritten);
307 }
308
309 gint64 
310 ves_icall_System_IO_FileStream_FileSeek (gpointer handle, gint64 offset, gint32 origin) {
311         gint64 ret;
312         gint32 offsetlo, offsethi, retlo;
313         
314         if(handle == INVALID_HANDLE_VALUE) {
315                 mono_raise_exception(mono_get_exception_io("Invalid handle"));
316         }
317
318         offsetlo=offset & 0xFFFFFFFF;
319         offsethi=offset >> 32;
320
321         retlo=SetFilePointer(handle, offset, &offsethi,
322                              convert_seekorigin(origin));
323         
324         ret=((gint64)offsethi << 32) + offsetlo;
325
326         return(ret);
327 }
328
329 gint64 
330 ves_icall_System_IO_FileStream_FileGetLength (gpointer handle) {
331         gint32 length_lo, length_hi;
332
333         if (handle == INVALID_HANDLE_VALUE)
334                 mono_raise_exception (mono_get_exception_io ("Invalid handle"));
335         
336         length_lo = GetFileSize (handle, &length_hi);
337         
338         return ((gint64)length_hi << 32) | length_lo;
339 }
340
341 void 
342 ves_icall_System_IO_FileStream_FileSetLength (gpointer handle, gint64 length) {
343         /* FIXME: Should this put the file pointer back to where it
344          * was before we started setting the length? The spec doesnt
345          * say, as usual
346          */
347
348         gboolean ret;
349         gint32 lenlo, lenhi, retlo;
350         
351         if(handle == INVALID_HANDLE_VALUE) {
352                 mono_raise_exception(mono_get_exception_io("Invalid handle"));
353         }
354
355         lenlo=length & 0xFFFFFFFF;
356         lenhi=length >> 32;
357
358         retlo=SetFilePointer(handle, lenlo, &lenhi, FILE_BEGIN);
359         ret=SetEndOfFile(handle);
360         
361         if(ret==FALSE) {
362                 mono_raise_exception(mono_get_exception_io("IO Exception"));
363         }
364 }
365
366 void 
367 ves_icall_System_IO_FileStream_FileFlush (gpointer handle) {
368         /* FIXME: implement FlushFileBuffers */
369 }
370