Wed Sep 11 12:53:28 CEST 2002 Paolo Molaro <lupus@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  *
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 #undef DEBUG
20
21 /* conversion functions */
22
23 static guint32 convert_mode(MonoFileMode mono_mode)
24 {
25         guint32 mode;
26
27         switch(mono_mode) {
28         case FileMode_CreateNew:
29                 mode=CREATE_NEW;
30                 break;
31         case FileMode_Create:
32                 mode=CREATE_ALWAYS;
33                 break;
34         case FileMode_Open:
35                 mode=OPEN_EXISTING;
36                 break;
37         case FileMode_OpenOrCreate:
38                 mode=OPEN_ALWAYS;
39                 break;
40         case FileMode_Truncate:
41                 mode=TRUNCATE_EXISTING;
42                 break;
43         case FileMode_Append:
44                 mode=OPEN_ALWAYS;
45                 break;
46         default:
47                 g_warning("System.IO.FileMode has unknown value 0x%x",
48                           mono_mode);
49                 /* Safe fallback */
50                 mode=OPEN_EXISTING;
51         }
52         
53         return(mode);
54 }
55
56 static guint32 convert_access(MonoFileAccess mono_access)
57 {
58         guint32 access;
59         
60         switch(mono_access) {
61         case FileAccess_Read:
62                 access=GENERIC_READ;
63                 break;
64         case FileAccess_Write:
65                 access=GENERIC_WRITE;
66                 break;
67         case FileAccess_ReadWrite:
68                 access=GENERIC_READ|GENERIC_WRITE;
69                 break;
70         default:
71                 g_warning("System.IO.FileAccess has unknown value 0x%x",
72                           mono_access);
73                 /* Safe fallback */
74                 access=GENERIC_READ;
75         }
76         
77         return(access);
78 }
79
80 static guint32 convert_share(MonoFileShare mono_share)
81 {
82         guint32 share;
83         
84         switch(mono_share) {
85         case FileShare_None:
86                 share=0;
87                 break;
88         case FileShare_Read:
89                 share=FILE_SHARE_READ;
90                 break;
91         case FileShare_Write:
92                 share=FILE_SHARE_WRITE;
93                 break;
94         case FileShare_ReadWrite:
95                 share=FILE_SHARE_READ|FILE_SHARE_WRITE;
96                 break;
97         default:
98                 g_warning("System.IO.FileShare has unknown value 0x%x",
99                           mono_share);
100                 /* Safe fallback */
101                 share=0;
102         }
103         
104         return(share);
105 }
106
107 #if 0
108 static guint32 convert_stdhandle(guint32 fd)
109 {
110         guint32 stdhandle;
111         
112         switch(fd) {
113         case 0:
114                 stdhandle=STD_INPUT_HANDLE;
115                 break;
116         case 1:
117                 stdhandle=STD_OUTPUT_HANDLE;
118                 break;
119         case 2:
120                 stdhandle=STD_ERROR_HANDLE;
121                 break;
122         default:
123                 g_warning("unknown standard file descriptor %d", fd);
124                 stdhandle=STD_INPUT_HANDLE;
125         }
126         
127         return(stdhandle);
128 }
129 #endif
130
131 static guint32 convert_seekorigin(MonoSeekOrigin origin)
132 {
133         guint32 w32origin;
134         
135         switch(origin) {
136         case SeekOrigin_Begin:
137                 w32origin=FILE_BEGIN;
138                 break;
139         case SeekOrigin_Current:
140                 w32origin=FILE_CURRENT;
141                 break;
142         case SeekOrigin_End:
143                 w32origin=FILE_END;
144                 break;
145         default:
146                 g_warning("System.IO.SeekOrigin has unknown value 0x%x",
147                           origin);
148                 /* Safe fallback */
149                 w32origin=FILE_CURRENT;
150         }
151         
152         return(w32origin);
153 }
154
155 static gint64 convert_filetime (const FILETIME *filetime)
156 {
157         gint64 *ticks;
158
159         ticks = (gint64 *)filetime;
160         return *ticks;
161 }
162
163 static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
164 {
165         int len;
166         
167         stat->attributes = data->dwFileAttributes;
168         stat->creation_time = convert_filetime (&data->ftCreationTime);
169         stat->last_access_time = convert_filetime (&data->ftLastAccessTime);
170         stat->last_write_time = convert_filetime (&data->ftLastWriteTime);
171         stat->length = ((gint64)data->nFileSizeHigh << 32) | data->nFileSizeLow;
172
173         len = 0;
174         while (name [len])
175                 ++ len;
176
177         stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
178 }
179
180 /* System.IO.MonoIO internal calls */
181
182 gint32 
183 ves_icall_System_IO_MonoIO_GetLastError ()
184 {
185         return GetLastError ();
186 }
187
188 gboolean 
189 ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path)
190 {
191         return CreateDirectory (mono_string_chars (path), NULL);
192 }
193
194 gboolean 
195 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path)
196 {
197         return RemoveDirectory (mono_string_chars (path));
198 }
199
200 HANDLE 
201 ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat)
202 {
203         WIN32_FIND_DATA data;
204         HANDLE result;
205
206         result = FindFirstFile (mono_string_chars (path), &data);
207
208         /* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
209
210         if (result != INVALID_HANDLE_VALUE)
211                 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
212                                                    &data.cFileName [0], stat);
213
214         return result;
215 }
216
217 gboolean 
218 ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat)
219 {
220         WIN32_FIND_DATA data;
221         gboolean result;
222
223         result = FindNextFile (find, &data);
224         if (result)
225                 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
226                                                    &data.cFileName [0], stat);
227
228         return result;
229 }
230
231 gboolean 
232 ves_icall_System_IO_MonoIO_FindClose (HANDLE find)
233 {
234         return FindClose (find);
235 }
236
237 MonoString *
238 ves_icall_System_IO_MonoIO_GetCurrentDirectory ()
239 {
240         MonoString *result;
241         gunichar2 *buf;
242         int len;
243
244         len = MAX_PATH + 1;
245         buf = g_new (gunichar2, len);
246         
247         result = NULL;
248         if (GetCurrentDirectory (len, buf) > 0) {
249                 len = 0;
250                 while (buf [len])
251                         ++ len;
252
253                 result = mono_string_new_utf16 (mono_domain_get (), buf, len);
254         }
255
256         g_free (buf);
257         return result;
258 }
259
260 gboolean 
261 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path)
262 {
263         return SetCurrentDirectory (mono_string_chars (path));
264 }
265
266 gboolean 
267 ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest)
268 {
269         return MoveFile (mono_string_chars (path), mono_string_chars (dest));
270 }
271
272 gboolean 
273 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest, gboolean overwrite)
274 {
275         return CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
276 }
277
278 gboolean 
279 ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path)
280 {
281         return DeleteFile (mono_string_chars (path));
282 }
283
284 gint32 
285 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path)
286 {
287         return GetFileAttributes (mono_string_chars (path));
288 }
289
290 gboolean
291 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs)
292 {
293         return SetFileAttributes (mono_string_chars (path), attrs);
294 }
295
296 gboolean 
297 ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat)
298 {
299         gboolean result;
300         WIN32_FILE_ATTRIBUTE_DATA data;
301
302         result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
303
304         if (result)
305                 convert_win32_file_attribute_data (&data, mono_string_chars (path), stat);
306
307         return result;
308 }
309
310 HANDLE 
311 ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode, gint32 access_mode, gint32 share)
312 {
313         return CreateFile (mono_string_chars (filename), convert_access (access_mode), convert_share (share),
314                              NULL, convert_mode (mode), FILE_ATTRIBUTE_NORMAL, NULL);
315 }
316
317 gboolean 
318 ves_icall_System_IO_MonoIO_Close (HANDLE handle)
319 {
320         return CloseHandle (handle);
321 }
322
323 gint32 
324 ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest, gint32 dest_offset, gint32 count)
325 {
326         guchar *buffer;
327         gboolean result;
328         guint32 n;
329
330         if (dest_offset + count > mono_array_length (dest))
331                 return 0;
332
333         buffer = mono_array_addr (dest, guchar, dest_offset);
334         result = ReadFile (handle, buffer, count, &n, NULL);
335
336         if (!result)
337                 return -1;
338
339         return (gint32)n;
340 }
341
342 gint32 
343 ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src, gint32 src_offset, gint32 count)
344 {
345         guchar *buffer;
346         gboolean result;
347         guint32 n;
348
349         if (src_offset + count > mono_array_length (src))
350                 return 0;
351         
352         buffer = mono_array_addr (src, guchar, src_offset);
353         result = WriteFile (handle, buffer, count, &n, NULL);
354
355         if (!result)
356                 return -1;
357
358         return (gint32)n;
359 }
360
361 gint64 
362 ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin)
363 {
364         guint32 offset_hi;
365
366         offset_hi = offset >> 32;
367         offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
368                                  convert_seekorigin (origin));
369
370         return offset | ((gint64)offset_hi << 32);
371 }
372
373 gboolean 
374 ves_icall_System_IO_MonoIO_Flush (HANDLE handle)
375 {
376         return FlushFileBuffers (handle);
377 }
378
379 gint64 
380 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle)
381 {
382         gint64 length;
383         guint32 length_hi;
384
385         length = GetFileSize (handle, &length_hi);
386         return length | ((gint64)length_hi << 32);
387 }
388
389 gboolean 
390 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length)
391 {
392         gint64 offset;
393         gint32 offset_hi;
394         gint32 length_hi;
395         gboolean result;
396
397         /* save file pointer */
398
399         offset_hi = 0;
400         offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
401
402         /* extend or truncate */
403
404         length_hi = length >> 32;
405         SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi, FILE_BEGIN);
406         result = SetEndOfFile (handle);
407
408         /* restore file pointer */
409
410         SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi, FILE_BEGIN);
411
412         return result;
413 }
414
415 gboolean
416 ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time, gint64 last_access_time, gint64 last_write_time)
417 {
418         const FILETIME *creation_filetime;
419         const FILETIME *last_access_filetime;
420         const FILETIME *last_write_filetime;
421
422         if (creation_time < 0)
423                 creation_filetime = NULL;
424         else
425                 creation_filetime = (FILETIME *)&creation_time;
426
427         if (last_access_time < 0)
428                 last_access_filetime = NULL;
429         else
430                 last_access_filetime = (FILETIME *)&last_access_time;
431
432         if (last_write_time < 0)
433                 last_write_filetime = NULL;
434         else
435                 last_write_filetime = (FILETIME *)&last_write_time;
436
437         return SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
438 }
439
440 HANDLE 
441 ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
442 {
443         return GetStdHandle (STD_OUTPUT_HANDLE);
444 }
445
446 HANDLE 
447 ves_icall_System_IO_MonoIO_get_ConsoleInput ()
448 {
449         return GetStdHandle (STD_INPUT_HANDLE);
450 }
451
452 HANDLE 
453 ves_icall_System_IO_MonoIO_get_ConsoleError ()
454 {
455         return GetStdHandle (STD_ERROR_HANDLE);
456 }
457
458 MonoBoolean
459 ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
460                                        HANDLE *write_handle)
461 {
462         SECURITY_ATTRIBUTES attr;
463         gboolean ret;
464         
465         attr.nLength=sizeof(SECURITY_ATTRIBUTES);
466         attr.bInheritHandle=TRUE;
467         attr.lpSecurityDescriptor=NULL;
468         
469         ret=CreatePipe (read_handle, write_handle, &attr, 0);
470         if(ret==FALSE) {
471                 /* FIXME: throw an exception? */
472                 return(FALSE);
473         }
474         
475         return(TRUE);
476 }
477
478 gunichar2 
479 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
480 {
481 #if defined (PLATFORM_WIN32)
482         return (gunichar2) 0x003a;      /* colon */
483 #else
484         return (gunichar2) 0x002f;      /* forward slash */
485 #endif
486 }
487
488 gunichar2 
489 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
490 {
491 #if defined (PLATFORM_WIN32)
492         return (gunichar2) 0x005c;      /* backslash */
493 #else
494         return (gunichar2) 0x002f;      /* forward slash */
495 #endif
496 }
497
498 gunichar2 
499 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
500 {
501 #if defined (PLATFORM_WIN32)
502         return (gunichar2) 0x002f;      /* forward slash */
503 #else
504         return (gunichar2) 0x005c;      /* backslash */
505 #endif
506 }
507
508 gunichar2 
509 ves_icall_System_IO_MonoIO_get_PathSeparator ()
510 {
511 #if defined (PLATFORM_WIN32)
512         return (gunichar2) 0x003b;      /* semicolon */
513 #else
514         return (gunichar2) 0x003a;      /* colon */
515 #endif
516 }
517
518 static gunichar2 invalid_path_chars [] = {
519 #if defined (PLATFORM_WIN32)
520         0x0022,                         /* double quote */
521         0x003c,                         /* less than */
522         0x003e,                         /* greater than */
523         0x007c,                         /* pipe */
524 #endif
525         0x0000                          /* null */
526 };
527
528 MonoArray *
529 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
530 {
531         MonoArray *chars;
532         MonoDomain *domain;
533         int i, n;
534
535         domain = mono_domain_get ();
536         chars = mono_array_new (domain, mono_defaults.char_class, 5);
537
538         n = sizeof (invalid_path_chars) / sizeof (gunichar2);
539
540         for (i = 0; i < n; ++ i)
541                 mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
542         
543         return chars;
544 }