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