2
* file-io.c: File IO internal calls
5
* Dick Porter (dick@ximian.com)
7
* (C) 2001 Ximian, Inc.
17
#ifndef PLATFORM_WIN32
21
#elif defined(HAVE_SYS_AIO_H)
29
#include <mono/metadata/object.h>
30
#include <mono/io-layer/io-layer.h>
31
#include <mono/metadata/file-io.h>
32
#include <mono/metadata/exception.h>
33
#include <mono/metadata/appdomain.h>
34
#include <mono/metadata/marshal.h>
38
/* conversion functions */
40
static guint32 convert_mode(MonoFileMode mono_mode)
45
case FileMode_CreateNew:
54
case FileMode_OpenOrCreate:
57
case FileMode_Truncate:
58
mode=TRUNCATE_EXISTING;
64
g_warning("System.IO.FileMode has unknown value 0x%x",
73
static guint32 convert_access(MonoFileAccess mono_access)
81
case FileAccess_Write:
84
case FileAccess_ReadWrite:
85
access=GENERIC_READ|GENERIC_WRITE;
88
g_warning("System.IO.FileAccess has unknown value 0x%x",
97
static guint32 convert_share(MonoFileShare mono_share)
106
share=FILE_SHARE_READ;
108
case FileShare_Write:
109
share=FILE_SHARE_WRITE;
111
case FileShare_ReadWrite:
112
share=FILE_SHARE_READ|FILE_SHARE_WRITE;
115
g_warning("System.IO.FileShare has unknown value 0x%x",
125
static guint32 convert_stdhandle(guint32 fd)
131
stdhandle=STD_INPUT_HANDLE;
134
stdhandle=STD_OUTPUT_HANDLE;
137
stdhandle=STD_ERROR_HANDLE;
140
g_warning("unknown standard file descriptor %d", fd);
141
stdhandle=STD_INPUT_HANDLE;
148
static guint32 convert_seekorigin(MonoSeekOrigin origin)
153
case SeekOrigin_Begin:
154
w32origin=FILE_BEGIN;
156
case SeekOrigin_Current:
157
w32origin=FILE_CURRENT;
163
g_warning("System.IO.SeekOrigin has unknown value 0x%x",
166
w32origin=FILE_CURRENT;
172
static gint64 convert_filetime (const FILETIME *filetime)
174
guint64 ticks = filetime->dwHighDateTime;
176
ticks += filetime->dwLowDateTime;
177
return (gint64)ticks;
180
static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
184
stat->attributes = data->dwFileAttributes;
185
stat->creation_time = convert_filetime (&data->ftCreationTime);
186
stat->last_access_time = convert_filetime (&data->ftLastAccessTime);
187
stat->last_write_time = convert_filetime (&data->ftLastWriteTime);
188
stat->length = ((gint64)data->nFileSizeHigh << 32) | data->nFileSizeLow;
194
stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
197
/* Managed file attributes have nearly but not quite the same values
198
* as the w32 equivalents.
200
static guint32 convert_attrs(MonoFileAttributes attrs)
202
if(attrs & FileAttributes_Encrypted) {
203
attrs |= FILE_ATTRIBUTE_ENCRYPTED;
209
/* System.IO.MonoIO internal calls */
212
ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
218
*error=ERROR_SUCCESS;
220
ret=CreateDirectory (mono_string_chars (path), NULL);
222
*error=GetLastError ();
229
ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
235
*error=ERROR_SUCCESS;
237
ret=RemoveDirectory (mono_string_chars (path));
239
*error=GetLastError ();
246
ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat,
249
WIN32_FIND_DATA data;
255
*error=ERROR_SUCCESS;
257
result = FindFirstFile (mono_string_chars (path), &data);
259
/* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
260
while (result != INVALID_HANDLE_VALUE && r) {
261
if ((data.cFileName [0] == '.' && data.cFileName [1] == 0) ||
262
(data.cFileName [0] == '.' && data.cFileName [1] == '.' && data.cFileName [2] == 0)) {
263
r = FindNextFile (result, &data);
265
convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
266
&data.cFileName [0], stat);
271
if (result == INVALID_HANDLE_VALUE) {
272
*error=GetLastError ();
276
/* No more files were found, after we discarded . and .. */
278
result = INVALID_HANDLE_VALUE;
279
*error = ERROR_NO_MORE_FILES;
286
ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat,
289
WIN32_FIND_DATA data;
294
*error=ERROR_SUCCESS;
296
result = FindNextFile (find, &data);
297
while (result != FALSE) {
298
if ((data.cFileName [0] == '.' && data.cFileName [1] == 0) ||
299
(data.cFileName [0] == '.' && data.cFileName [1] == '.' && data.cFileName [2] == 0)) {
300
result = FindNextFile (find, &data);
302
convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
303
&data.cFileName [0], stat);
308
if (result == FALSE) {
309
*error=GetLastError ();
316
ves_icall_System_IO_MonoIO_FindClose (HANDLE find, gint32 *error)
322
*error=ERROR_SUCCESS;
324
ret=FindClose (find);
326
*error=GetLastError ();
333
ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
342
buf = g_new (gunichar2, len);
344
*error=ERROR_SUCCESS;
347
if (GetCurrentDirectory (len, buf) > 0) {
352
result = mono_string_new_utf16 (mono_domain_get (), buf, len);
354
*error=GetLastError ();
362
ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
369
*error=ERROR_SUCCESS;
371
ret=SetCurrentDirectory (mono_string_chars (path));
373
*error=GetLastError ();
380
ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
387
*error=ERROR_SUCCESS;
389
ret=MoveFile (mono_string_chars (path), mono_string_chars (dest));
391
*error=GetLastError ();
398
ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
399
MonoBoolean overwrite, gint32 *error)
405
*error=ERROR_SUCCESS;
407
ret=CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
409
*error=GetLastError ();
416
ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
422
*error=ERROR_SUCCESS;
424
ret=DeleteFile (mono_string_chars (path));
426
*error=GetLastError ();
433
ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
439
*error=ERROR_SUCCESS;
441
ret=GetFileAttributes (mono_string_chars (path));
444
* The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
445
* headers is wrong, hence this temporary workaround.
447
* http://cygwin.com/ml/cygwin/2003-09/msg01771.html
450
// if(ret==INVALID_FILE_ATTRIBUTES) {
451
*error=GetLastError ();
458
ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
465
*error=ERROR_SUCCESS;
467
ret=SetFileAttributes (mono_string_chars (path),
468
convert_attrs (attrs));
470
*error=GetLastError ();
477
ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
483
*error=ERROR_SUCCESS;
485
ret=GetFileType (handle);
486
if(ret==FILE_TYPE_UNKNOWN) {
487
/* Not necessarily an error, but the caller will have
488
* to decide based on the error value.
490
*error=GetLastError ();
497
ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
501
WIN32_FILE_ATTRIBUTE_DATA data;
505
*error=ERROR_SUCCESS;
507
result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
510
convert_win32_file_attribute_data (&data,
511
mono_string_chars (path),
514
*error=GetLastError ();
521
ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
522
gint32 access_mode, gint32 share,
523
MonoBoolean async, gint32 *error)
529
*error=ERROR_SUCCESS;
531
ret=CreateFile (mono_string_chars (filename),
532
convert_access (access_mode), convert_share (share),
533
NULL, convert_mode (mode),
534
FILE_ATTRIBUTE_NORMAL | ((async) ? FILE_FLAG_OVERLAPPED : 0),
536
if(ret==INVALID_HANDLE_VALUE) {
537
*error=GetLastError ();
544
ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
550
*error=ERROR_SUCCESS;
552
ret=CloseHandle (handle);
554
*error=GetLastError ();
561
ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
562
gint32 dest_offset, gint32 count,
571
*error=ERROR_SUCCESS;
573
if (dest_offset + count > mono_array_length (dest))
576
buffer = mono_array_addr (dest, guchar, dest_offset);
577
result = ReadFile (handle, buffer, count, &n, NULL);
580
*error=GetLastError ();
588
ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
589
gint32 src_offset, gint32 count,
598
*error=ERROR_SUCCESS;
600
if (src_offset + count > mono_array_length (src))
603
buffer = mono_array_addr (src, guchar, src_offset);
604
result = WriteFile (handle, buffer, count, &n, NULL);
607
*error=GetLastError ();
615
ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
622
*error=ERROR_SUCCESS;
624
offset_hi = offset >> 32;
625
offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
626
convert_seekorigin (origin));
628
if(offset==INVALID_SET_FILE_POINTER) {
629
*error=GetLastError ();
632
return offset | ((gint64)offset_hi << 32);
636
ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
642
*error=ERROR_SUCCESS;
644
ret=FlushFileBuffers (handle);
646
*error=GetLastError ();
653
ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
660
*error=ERROR_SUCCESS;
662
length = GetFileSize (handle, &length_hi);
663
if(length==INVALID_FILE_SIZE) {
664
*error=GetLastError ();
667
return length | ((gint64)length_hi << 32);
671
ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
674
gint64 offset, offset_set;
681
*error=ERROR_SUCCESS;
683
/* save file pointer */
686
offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
687
if(offset==INVALID_SET_FILE_POINTER) {
688
*error=GetLastError ();
692
/* extend or truncate */
694
length_hi = length >> 32;
695
offset_set=SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi,
697
if(offset_set==INVALID_SET_FILE_POINTER) {
698
*error=GetLastError ();
702
result = SetEndOfFile (handle);
704
*error=GetLastError ();
708
/* restore file pointer */
710
offset_set=SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
712
if(offset_set==INVALID_SET_FILE_POINTER) {
713
*error=GetLastError ();
721
ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
722
gint64 last_access_time,
723
gint64 last_write_time, gint32 *error)
726
const FILETIME *creation_filetime;
727
const FILETIME *last_access_filetime;
728
const FILETIME *last_write_filetime;
732
*error=ERROR_SUCCESS;
734
if (creation_time < 0)
735
creation_filetime = NULL;
737
creation_filetime = (FILETIME *)&creation_time;
739
if (last_access_time < 0)
740
last_access_filetime = NULL;
742
last_access_filetime = (FILETIME *)&last_access_time;
744
if (last_write_time < 0)
745
last_write_filetime = NULL;
747
last_write_filetime = (FILETIME *)&last_write_time;
749
ret=SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
751
*error=GetLastError ();
758
ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
762
return GetStdHandle (STD_OUTPUT_HANDLE);
766
ves_icall_System_IO_MonoIO_get_ConsoleInput ()
770
return GetStdHandle (STD_INPUT_HANDLE);
774
ves_icall_System_IO_MonoIO_get_ConsoleError ()
778
return GetStdHandle (STD_ERROR_HANDLE);
782
ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
783
HANDLE *write_handle)
785
SECURITY_ATTRIBUTES attr;
790
attr.nLength=sizeof(SECURITY_ATTRIBUTES);
791
attr.bInheritHandle=TRUE;
792
attr.lpSecurityDescriptor=NULL;
794
ret=CreatePipe (read_handle, write_handle, &attr, 0);
796
/* FIXME: throw an exception? */
804
ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
808
#if defined (PLATFORM_WIN32)
809
return (gunichar2) 0x003a; /* colon */
811
return (gunichar2) 0x002f; /* forward slash */
816
ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
820
#if defined (PLATFORM_WIN32)
821
return (gunichar2) 0x005c; /* backslash */
823
return (gunichar2) 0x002f; /* forward slash */
828
ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
832
#if defined (PLATFORM_WIN32)
833
return (gunichar2) 0x002f; /* forward slash */
835
return (gunichar2) 0x005c; /* backslash */
840
ves_icall_System_IO_MonoIO_get_PathSeparator ()
844
#if defined (PLATFORM_WIN32)
845
return (gunichar2) 0x003b; /* semicolon */
847
return (gunichar2) 0x003a; /* colon */
851
static gunichar2 invalid_path_chars [] = {
852
#if defined (PLATFORM_WIN32)
853
0x0022, /* double quote, which seems allowed in MS.NET but should be rejected */
854
0x003c, /* less than */
855
0x003e, /* greater than */
872
ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
880
domain = mono_domain_get ();
881
chars = mono_array_new (domain, mono_defaults.char_class, 15);
883
n = sizeof (invalid_path_chars) / sizeof (gunichar2);
885
for (i = 0; i < n; ++ i)
886
mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
892
ves_icall_System_IO_MonoIO_GetTempPath (MonoString **mono_name)
897
name=g_new0 (gunichar2, 256);
899
ret=GetTempPath (256, name);
901
/* Buffer was too short. Try again... */
903
name=g_new0 (gunichar2, ret+2); /* include the terminator */
904
ret=GetTempPath (ret, name);
909
g_message (G_GNUC_PRETTY_FUNCTION
910
": Temp path is [%s] (len %d)", name, ret);
913
*mono_name=mono_string_new_utf16 (mono_domain_get (), name,
926
ves_icall_System_IO_MonoIO_GetSupportsAsync (void)
930
#ifdef PLATFORM_WIN32
931
/* Seems like BindIoCompletionCallback is not found when compiling...
932
* Disabling AIO support on win. Any one wants to fix this?
935
/* return (g_getenv ("MONO_DISABLE_AIO") == NULL && WINVER >= 0x500); */
936
#elif defined(USE_AIO)
937
if (aio_cancel (-1, NULL) == -1 && errno == ENOSYS)
940
return (g_getenv ("MONO_DISABLE_AIO") == NULL);
946
static WapiOverlapped *
947
get_overlapped_from_fsa (MonoFSAsyncResult *ares)
951
ovl = g_new0 (WapiOverlapped, 1);
952
ovl->Offset = ares->offset;
953
ovl->hEvent = ares->wait_handle;
959
ves_icall_System_IO_MonoIO_BeginRead (HANDLE handle, MonoFSAsyncResult *ares)
966
ovl = get_overlapped_from_fsa (ares);
968
return ReadFile (handle, mono_array_addr (ares->buffer, gchar, ares->offset), ares->count, &bytesread, ovl);
972
ves_icall_System_IO_MonoIO_BeginWrite (HANDLE handle, MonoFSAsyncResult *ares)
974
guint32 byteswritten;
979
ovl = get_overlapped_from_fsa (ares);
981
return WriteFile (handle, mono_array_addr (ares->buffer, gchar, ares->offset), ares->count, &byteswritten, ovl);
984
void ves_icall_System_IO_MonoIO_Lock (HANDLE handle, gint64 position,
985
gint64 length, gint32 *error)
989
*error=ERROR_SUCCESS;
991
ret=LockFile (handle, position & 0xFFFFFFFF, position >> 32,
992
length & 0xFFFFFFFF, length >> 32);
994
*error = GetLastError ();
998
void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
999
gint64 length, gint32 *error)
1003
*error=ERROR_SUCCESS;
1005
ret=UnlockFile (handle, position & 0xFFFFFFFF, position >> 32,
1006
length & 0xFFFFFFFF, length >> 32);
1008
*error = GetLastError ();