2002-05-15 Radek Doulik <rodo@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 #define 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         gunichar2 *utf16_path;
192         gboolean result;
193
194         utf16_path = mono_string_to_utf16 (path);
195         result = CreateDirectory (utf16_path, NULL);
196         g_free (utf16_path);
197
198         return result;
199 }
200
201 gboolean 
202 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path)
203 {
204         gunichar2 *utf16_path;
205         gboolean result;
206
207         utf16_path = mono_string_to_utf16 (path);
208         result = RemoveDirectory (utf16_path);
209         g_free (utf16_path);
210
211         return result;
212 }
213
214 HANDLE 
215 ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat)
216 {
217         gunichar2 *utf16_path;
218         WIN32_FIND_DATA data;
219         HANDLE result;
220
221         utf16_path = mono_string_to_utf16 (path);
222         result = FindFirstFile (utf16_path, &data);
223         g_free (utf16_path);
224
225         /* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
226
227         if (result != INVALID_HANDLE_VALUE)
228                 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
229                                                    &data.cFileName [0], stat);
230
231         return result;
232 }
233
234 gboolean 
235 ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat)
236 {
237         WIN32_FIND_DATA data;
238         gboolean result;
239
240         result = FindNextFile (find, &data);
241         if (result)
242                 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
243                                                    &data.cFileName [0], stat);
244
245         return result;
246 }
247
248 gboolean 
249 ves_icall_System_IO_MonoIO_FindClose (HANDLE find)
250 {
251         return FindClose (find);
252 }
253
254 MonoString *
255 ves_icall_System_IO_MonoIO_GetCurrentDirectory ()
256 {
257         MonoString *result;
258         gunichar2 *buf;
259         int len;
260
261         len = MAX_PATH + 1;
262         buf = g_new (gunichar2, len);
263         
264         result = NULL;
265         if (GetCurrentDirectory (len, buf) > 0) {
266                 len = 0;
267                 while (buf [len])
268                         ++ len;
269
270                 result = mono_string_new_utf16 (mono_domain_get (), buf, len);
271         }
272
273         g_free (buf);
274         return result;
275 }
276
277 gboolean 
278 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path)
279 {
280         gunichar2 *utf16_path;
281         gboolean result;
282         
283         utf16_path = mono_string_to_utf16 (path);
284         result = SetCurrentDirectory (utf16_path);
285         g_free (utf16_path);
286
287         return result;
288 }
289
290 gboolean 
291 ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest)
292 {
293         gunichar2 *utf16_path, *utf16_dest;
294         gboolean result;
295
296         utf16_path = mono_string_to_utf16 (path);
297         utf16_dest = mono_string_to_utf16 (dest);
298         result = MoveFile (utf16_path, utf16_dest);
299         g_free (utf16_path);
300         g_free (utf16_dest);
301
302         return result;
303 }
304
305 gboolean 
306 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest, gboolean overwrite)
307 {
308         gunichar2 *utf16_path, *utf16_dest;
309         gboolean result;
310
311         utf16_path = mono_string_to_utf16 (path);
312         utf16_dest = mono_string_to_utf16 (dest);
313         result = CopyFile (utf16_path, utf16_dest, !overwrite);
314         g_free (utf16_path);
315         g_free (utf16_dest);
316
317         return result;
318 }
319
320 gboolean 
321 ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path)
322 {
323         gunichar2 *utf16_path;
324         gboolean result;
325
326         utf16_path = mono_string_to_utf16 (path);
327         result = DeleteFile (utf16_path);
328         g_free (utf16_path);
329
330         return result;
331 }
332
333 gint32 
334 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path)
335 {
336         gunichar2 *utf16_path;
337         gint32 result;
338
339         utf16_path = mono_string_to_utf16 (path);
340         result = GetFileAttributes (utf16_path);
341         g_free (utf16_path);
342
343         return result;
344 }
345
346 gboolean
347 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs)
348 {
349         gunichar2 *utf16_path;
350         gboolean result;
351
352         utf16_path = mono_string_to_utf16 (path);
353         result = SetFileAttributes (utf16_path, attrs);
354         g_free (utf16_path);
355
356         return result;
357 }
358
359 gboolean 
360 ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat)
361 {
362         gunichar2 *utf16_path;
363         gboolean result;
364         WIN32_FILE_ATTRIBUTE_DATA data;
365
366         utf16_path = mono_string_to_utf16 (path);
367         result = GetFileAttributesEx (utf16_path, GetFileExInfoStandard, &data);
368         g_free (utf16_path);
369
370         if (result)
371                 convert_win32_file_attribute_data (&data, utf16_path, stat);
372
373         return result;
374 }
375
376 HANDLE 
377 ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode, gint32 access_mode, gint32 share)
378 {
379         gunichar2 *utf16_filename;
380         HANDLE result;
381
382         utf16_filename = mono_string_to_utf16 (filename);
383         result = CreateFile (utf16_filename, convert_access (access_mode), convert_share (share),
384                              NULL, convert_mode (mode), FILE_ATTRIBUTE_NORMAL, NULL);
385         g_free (utf16_filename);
386
387         return result;
388 }
389
390 gboolean 
391 ves_icall_System_IO_MonoIO_Close (HANDLE handle)
392 {
393         return CloseHandle (handle);
394 }
395
396 gint32 
397 ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest, gint32 dest_offset, gint32 count)
398 {
399         guchar *buffer;
400         gboolean result;
401         guint32 n;
402
403         if (dest_offset + count > mono_array_length (dest))
404                 return 0;
405
406         buffer = mono_array_addr (dest, guchar, dest_offset);
407         result = ReadFile (handle, buffer, count, &n, NULL);
408
409         if (!result)
410                 return -1;
411
412         return (gint32)n;
413 }
414
415 gint32 
416 ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src, gint32 src_offset, gint32 count)
417 {
418         guchar *buffer;
419         gboolean result;
420         guint32 n;
421
422         if (src_offset + count > mono_array_length (src))
423                 return 0;
424         
425         buffer = mono_array_addr (src, guchar, src_offset);
426         result = WriteFile (handle, buffer, count, &n, NULL);
427
428         if (!result)
429                 return -1;
430
431         return (gint32)n;
432 }
433
434 gint64 
435 ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin)
436 {
437         guint32 offset_hi;
438
439         offset_hi = offset >> 32;
440         offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
441                                  convert_seekorigin (origin));
442
443         return offset | ((gint64)offset_hi << 32);
444 }
445
446 gboolean 
447 ves_icall_System_IO_MonoIO_Flush (HANDLE handle)
448 {
449         return FlushFileBuffers (handle);
450 }
451
452 gint64 
453 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle)
454 {
455         gint64 length;
456         guint32 length_hi;
457
458         length = GetFileSize (handle, &length_hi);
459         return length | ((gint64)length_hi << 32);
460 }
461
462 gboolean 
463 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length)
464 {
465         gint64 offset;
466         gint32 offset_hi;
467         gint32 length_hi;
468         gboolean result;
469
470         /* save file pointer */
471
472         offset_hi = 0;
473         offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
474
475         /* extend or truncate */
476
477         length_hi = length >> 32;
478         SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi, FILE_BEGIN);
479         result = SetEndOfFile (handle);
480
481         /* restore file pointer */
482
483         SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi, FILE_BEGIN);
484
485         return result;
486 }
487
488 gboolean
489 ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time, gint64 last_access_time, gint64 last_write_time)
490 {
491         const FILETIME *creation_filetime;
492         const FILETIME *last_access_filetime;
493         const FILETIME *last_write_filetime;
494
495         if (creation_time < 0)
496                 creation_filetime = NULL;
497         else
498                 creation_filetime = (FILETIME *)&creation_time;
499
500         if (last_access_time < 0)
501                 last_access_filetime = NULL;
502         else
503                 last_access_filetime = (FILETIME *)&last_access_time;
504
505         if (last_write_time < 0)
506                 last_write_filetime = NULL;
507         else
508                 last_write_filetime = (FILETIME *)&last_write_time;
509
510         return SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
511 }
512
513 HANDLE 
514 ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
515 {
516         return GetStdHandle (STD_OUTPUT_HANDLE);
517 }
518
519 HANDLE 
520 ves_icall_System_IO_MonoIO_get_ConsoleInput ()
521 {
522         return GetStdHandle (STD_INPUT_HANDLE);
523 }
524
525 HANDLE 
526 ves_icall_System_IO_MonoIO_get_ConsoleError ()
527 {
528         return GetStdHandle (STD_ERROR_HANDLE);
529 }
530
531 gunichar2 
532 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
533 {
534 #if defined (PLATFORM_WIN32)
535         return (gunichar2) 0x003a;      /* colon */
536 #else
537         return (gunichar2) 0x002f;      /* forward slash */
538 #endif
539 }
540
541 gunichar2 
542 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
543 {
544 #if defined (PLATFORM_WIN32)
545         return (gunichar2) 0x005c;      /* backslash */
546 #else
547         return (gunichar2) 0x002f;      /* forward slash */
548 #endif
549 }
550
551 gunichar2 
552 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
553 {
554 #if defined (PLATFORM_WIN32)
555         return (gunichar2) 0x002f;      /* forward slash */
556 #else
557         return (gunichar2) 0x005c;      /* backslash */
558 #endif
559 }
560
561 gunichar2 
562 ves_icall_System_IO_MonoIO_get_PathSeparator ()
563 {
564 #if defined (PLATFORM_WIN32)
565         return (gunichar2) 0x003b;      /* semicolon */
566 #else
567         return (gunichar2) 0x003a;      /* colon */
568 #endif
569 }
570
571 static gunichar2 invalid_path_chars [] = {
572 #if defined (PLATFORM_WIN32)
573         0x0022,                         /* double quote */
574         0x003c,                         /* less than */
575         0x003e,                         /* greater than */
576         0x007c,                         /* pipe */
577 #endif
578         0x0000                          /* null */
579 };
580
581 MonoArray *
582 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
583 {
584         MonoArray *chars;
585         MonoDomain *domain;
586         int i, n;
587
588         domain = mono_domain_get ();
589         chars = mono_array_new (domain, mono_defaults.char_class, 5);
590
591         n = sizeof (invalid_path_chars) / sizeof (gunichar2);
592
593         for (i = 0; i < n; ++ i)
594                 mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
595         
596         return chars;
597 }