2 * file-io.c: File IO internal calls
5 * Dick Porter (dick@ximian.com)
7 * (C) 2001 Ximian, Inc.
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>
21 /* conversion functions */
23 static guint32 convert_mode(MonoFileMode mono_mode)
28 case FileMode_CreateNew:
37 case FileMode_OpenOrCreate:
40 case FileMode_Truncate:
41 mode=TRUNCATE_EXISTING;
47 g_warning("System.IO.FileMode has unknown value 0x%x",
56 static guint32 convert_access(MonoFileAccess mono_access)
64 case FileAccess_Write:
67 case FileAccess_ReadWrite:
68 access=GENERIC_READ|GENERIC_WRITE;
71 g_warning("System.IO.FileAccess has unknown value 0x%x",
80 static guint32 convert_share(MonoFileShare mono_share)
89 share=FILE_SHARE_READ;
92 share=FILE_SHARE_WRITE;
94 case FileShare_ReadWrite:
95 share=FILE_SHARE_READ|FILE_SHARE_WRITE;
98 g_warning("System.IO.FileShare has unknown value 0x%x",
108 static guint32 convert_stdhandle(guint32 fd)
114 stdhandle=STD_INPUT_HANDLE;
117 stdhandle=STD_OUTPUT_HANDLE;
120 stdhandle=STD_ERROR_HANDLE;
123 g_warning("unknown standard file descriptor %d", fd);
124 stdhandle=STD_INPUT_HANDLE;
131 static guint32 convert_seekorigin(MonoSeekOrigin origin)
136 case SeekOrigin_Begin:
137 w32origin=FILE_BEGIN;
139 case SeekOrigin_Current:
140 w32origin=FILE_CURRENT;
146 g_warning("System.IO.SeekOrigin has unknown value 0x%x",
149 w32origin=FILE_CURRENT;
155 static gint64 convert_filetime (const FILETIME *filetime)
157 guint64 ticks = filetime->dwHighDateTime;
159 ticks += filetime->dwLowDateTime;
160 return (gint64)ticks;
163 static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
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;
177 stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
180 /* Managed file attributes have nearly but not quite the same values
181 * as the w32 equivalents.
183 static guint32 convert_attrs(MonoFileAttributes attrs)
185 if(attrs & FileAttributes_Encrypted) {
186 attrs |= FILE_ATTRIBUTE_ENCRYPTED;
192 /* System.IO.MonoIO internal calls */
195 ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
201 *error=ERROR_SUCCESS;
203 ret=CreateDirectory (mono_string_chars (path), NULL);
205 *error=GetLastError ();
212 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
218 *error=ERROR_SUCCESS;
220 ret=RemoveDirectory (mono_string_chars (path));
222 *error=GetLastError ();
229 ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat,
232 WIN32_FIND_DATA data;
237 *error=ERROR_SUCCESS;
239 result = FindFirstFile (mono_string_chars (path), &data);
241 /* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
243 if (result != INVALID_HANDLE_VALUE) {
244 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
245 &data.cFileName [0], stat);
247 *error=GetLastError ();
254 ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat,
257 WIN32_FIND_DATA data;
262 *error=ERROR_SUCCESS;
264 result = FindNextFile (find, &data);
266 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
267 &data.cFileName [0], stat);
269 *error=GetLastError ();
276 ves_icall_System_IO_MonoIO_FindClose (HANDLE find, gint32 *error)
282 *error=ERROR_SUCCESS;
284 ret=FindClose (find);
286 *error=GetLastError ();
293 ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
302 buf = g_new (gunichar2, len);
304 *error=ERROR_SUCCESS;
307 if (GetCurrentDirectory (len, buf) > 0) {
312 result = mono_string_new_utf16 (mono_domain_get (), buf, len);
314 *error=GetLastError ();
322 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
329 *error=ERROR_SUCCESS;
331 ret=SetCurrentDirectory (mono_string_chars (path));
333 *error=GetLastError ();
340 ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
347 *error=ERROR_SUCCESS;
349 ret=MoveFile (mono_string_chars (path), mono_string_chars (dest));
351 *error=GetLastError ();
358 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
359 MonoBoolean overwrite, gint32 *error)
365 *error=ERROR_SUCCESS;
367 ret=CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
369 *error=GetLastError ();
376 ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
382 *error=ERROR_SUCCESS;
384 ret=DeleteFile (mono_string_chars (path));
386 *error=GetLastError ();
393 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
399 *error=ERROR_SUCCESS;
401 ret=GetFileAttributes (mono_string_chars (path));
404 * The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
405 * headers is wrong, hence this temporary workaround.
407 * http://cygwin.com/ml/cygwin/2003-09/msg01771.html
410 // if(ret==INVALID_FILE_ATTRIBUTES) {
411 *error=GetLastError ();
418 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
425 *error=ERROR_SUCCESS;
427 ret=SetFileAttributes (mono_string_chars (path),
428 convert_attrs (attrs));
430 *error=GetLastError ();
437 ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
443 *error=ERROR_SUCCESS;
445 ret=GetFileType (handle);
446 if(ret==FILE_TYPE_UNKNOWN) {
447 /* Not necessarily an error, but the caller will have
448 * to decide based on the error value.
450 *error=GetLastError ();
457 ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
461 WIN32_FILE_ATTRIBUTE_DATA data;
465 *error=ERROR_SUCCESS;
467 result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
470 convert_win32_file_attribute_data (&data,
471 mono_string_chars (path),
474 *error=GetLastError ();
481 ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
482 gint32 access_mode, gint32 share,
489 *error=ERROR_SUCCESS;
491 ret=CreateFile (mono_string_chars (filename),
492 convert_access (access_mode), convert_share (share),
493 NULL, convert_mode (mode), FILE_ATTRIBUTE_NORMAL,
495 if(ret==INVALID_HANDLE_VALUE) {
496 *error=GetLastError ();
503 ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
509 *error=ERROR_SUCCESS;
511 ret=CloseHandle (handle);
513 *error=GetLastError ();
520 ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
521 gint32 dest_offset, gint32 count,
530 *error=ERROR_SUCCESS;
532 if (dest_offset + count > mono_array_length (dest))
535 buffer = mono_array_addr (dest, guchar, dest_offset);
536 result = ReadFile (handle, buffer, count, &n, NULL);
539 *error=GetLastError ();
547 ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
548 gint32 src_offset, gint32 count,
557 *error=ERROR_SUCCESS;
559 if (src_offset + count > mono_array_length (src))
562 buffer = mono_array_addr (src, guchar, src_offset);
563 result = WriteFile (handle, buffer, count, &n, NULL);
566 *error=GetLastError ();
574 ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
581 *error=ERROR_SUCCESS;
583 offset_hi = offset >> 32;
584 offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
585 convert_seekorigin (origin));
587 if(offset==INVALID_SET_FILE_POINTER) {
588 *error=GetLastError ();
591 return offset | ((gint64)offset_hi << 32);
595 ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
601 *error=ERROR_SUCCESS;
603 ret=FlushFileBuffers (handle);
605 *error=GetLastError ();
612 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
619 *error=ERROR_SUCCESS;
621 length = GetFileSize (handle, &length_hi);
622 if(length==INVALID_FILE_SIZE) {
623 *error=GetLastError ();
626 return length | ((gint64)length_hi << 32);
630 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
633 gint64 offset, offset_set;
640 *error=ERROR_SUCCESS;
642 /* save file pointer */
645 offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
646 if(offset==INVALID_SET_FILE_POINTER) {
647 *error=GetLastError ();
651 /* extend or truncate */
653 length_hi = length >> 32;
654 offset_set=SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi,
656 if(offset_set==INVALID_SET_FILE_POINTER) {
657 *error=GetLastError ();
661 result = SetEndOfFile (handle);
663 *error=GetLastError ();
667 /* restore file pointer */
669 offset_set=SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
671 if(offset_set==INVALID_SET_FILE_POINTER) {
672 *error=GetLastError ();
680 ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
681 gint64 last_access_time,
682 gint64 last_write_time, gint32 *error)
685 const FILETIME *creation_filetime;
686 const FILETIME *last_access_filetime;
687 const FILETIME *last_write_filetime;
691 *error=ERROR_SUCCESS;
693 if (creation_time < 0)
694 creation_filetime = NULL;
696 creation_filetime = (FILETIME *)&creation_time;
698 if (last_access_time < 0)
699 last_access_filetime = NULL;
701 last_access_filetime = (FILETIME *)&last_access_time;
703 if (last_write_time < 0)
704 last_write_filetime = NULL;
706 last_write_filetime = (FILETIME *)&last_write_time;
708 ret=SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
710 *error=GetLastError ();
717 ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
721 return GetStdHandle (STD_OUTPUT_HANDLE);
725 ves_icall_System_IO_MonoIO_get_ConsoleInput ()
729 return GetStdHandle (STD_INPUT_HANDLE);
733 ves_icall_System_IO_MonoIO_get_ConsoleError ()
737 return GetStdHandle (STD_ERROR_HANDLE);
741 ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
742 HANDLE *write_handle)
744 SECURITY_ATTRIBUTES attr;
749 attr.nLength=sizeof(SECURITY_ATTRIBUTES);
750 attr.bInheritHandle=TRUE;
751 attr.lpSecurityDescriptor=NULL;
753 ret=CreatePipe (read_handle, write_handle, &attr, 0);
755 /* FIXME: throw an exception? */
763 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
767 #if defined (PLATFORM_WIN32)
768 return (gunichar2) 0x003a; /* colon */
770 return (gunichar2) 0x002f; /* forward slash */
775 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
779 #if defined (PLATFORM_WIN32)
780 return (gunichar2) 0x005c; /* backslash */
782 return (gunichar2) 0x002f; /* forward slash */
787 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
791 #if defined (PLATFORM_WIN32)
792 return (gunichar2) 0x002f; /* forward slash */
794 return (gunichar2) 0x005c; /* backslash */
799 ves_icall_System_IO_MonoIO_get_PathSeparator ()
803 #if defined (PLATFORM_WIN32)
804 return (gunichar2) 0x003b; /* semicolon */
806 return (gunichar2) 0x003a; /* colon */
810 static gunichar2 invalid_path_chars [] = {
811 #if defined (PLATFORM_WIN32)
812 0x0022, /* double quote, which seems allowed in MS.NET but should be rejected */
813 0x003c, /* less than */
814 0x003e, /* greater than */
831 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
839 domain = mono_domain_get ();
840 chars = mono_array_new (domain, mono_defaults.char_class, 15);
842 n = sizeof (invalid_path_chars) / sizeof (gunichar2);
844 for (i = 0; i < n; ++ i)
845 mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
851 ves_icall_System_IO_MonoIO_GetTempPath (MonoString **mono_name)
856 name=g_new0 (gunichar2, 256);
858 ret=GetTempPath (256, name);
860 /* Buffer was too short. Try again... */
862 name=g_new0 (gunichar2, ret+2); /* include the terminator */
863 ret=GetTempPath (ret, name);
868 g_message (G_GNUC_PRETTY_FUNCTION
869 ": Temp path is [%s] (len %d)", name, ret);
872 *mono_name=mono_string_new_utf16 (mono_domain_get (), name,