*
* Author:
* Dick Porter (dick@ximian.com)
+ * Gonzalo Paniagua Javier (gonzalo@ximian.com)
*
- * (C) 2001 Ximian, Inc.
+ * (C) 2001,2002,2003 Ximian, Inc.
+ * Copyright (c) 2004,2005 Novell, Inc. (http://www.novell.com)
*/
#include <config.h>
#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
#include <mono/metadata/object.h>
#include <mono/io-layer/io-layer.h>
#include <mono/metadata/file-io.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/appdomain.h>
+#include <mono/metadata/marshal.h>
+#include <mono/utils/strenc.h>
-#define DEBUG
+#undef DEBUG
+
+/* conversion functions */
static guint32 convert_mode(MonoFileMode mono_mode)
{
return(share);
}
+#if 0
static guint32 convert_stdhandle(guint32 fd)
{
guint32 stdhandle;
return(stdhandle);
}
+#endif
static guint32 convert_seekorigin(MonoSeekOrigin origin)
{
return(w32origin);
}
-/* fd must be one of stdin (value 0), stdout (1) or stderr (2). These
- * values must be hardcoded in corlib.
- */
-HANDLE ves_icall_System_PAL_OpSys_GetStdHandle(MonoObject *this,
- gint32 fd)
+static gint64 convert_filetime (const FILETIME *filetime)
+{
+ guint64 ticks = filetime->dwHighDateTime;
+ ticks <<= 32;
+ ticks += filetime->dwLowDateTime;
+ return (gint64)ticks;
+}
+
+static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
{
- HANDLE handle;
+ int len;
+
+ stat->attributes = data->dwFileAttributes;
+ stat->creation_time = convert_filetime (&data->ftCreationTime);
+ stat->last_access_time = convert_filetime (&data->ftLastAccessTime);
+ stat->last_write_time = convert_filetime (&data->ftLastWriteTime);
+ stat->length = ((gint64)data->nFileSizeHigh << 32) | data->nFileSizeLow;
+
+ len = 0;
+ while (name [len])
+ ++ len;
+
+ stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
+}
- if(fd!=0 && fd!=1 && fd!=2) {
- mono_raise_exception(mono_get_exception_io("Invalid file descriptor"));
+/* Managed file attributes have nearly but not quite the same values
+ * as the w32 equivalents.
+ */
+static guint32 convert_attrs(MonoFileAttributes attrs)
+{
+ if(attrs & FileAttributes_Encrypted) {
+ attrs |= FILE_ATTRIBUTE_ENCRYPTED;
}
- handle=GetStdHandle(convert_stdhandle(fd));
+ return(attrs);
+}
+
+/* System.IO.MonoIO internal calls */
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
+{
+ gboolean ret;
+
+ MONO_ARCH_SAVE_REGS;
+
+ *error=ERROR_SUCCESS;
- return(handle);
+ ret=CreateDirectory (mono_string_chars (path), NULL);
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ return(ret);
}
-void ves_icall_System_PAL_OpSys_DeleteFile(MonoObject *this, MonoString *path)
+MonoBoolean
+ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
{
- char *filename;
+ gboolean ret;
- filename=mono_string_to_utf16(path);
+ MONO_ARCH_SAVE_REGS;
+
+ *error=ERROR_SUCCESS;
+
+ ret=RemoveDirectory (mono_string_chars (path));
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ return(ret);
+}
+
+static gint
+get_error_from_g_file_error (gint error)
+{
+ switch (error) {
+ case G_FILE_ERROR_ACCES:
+ error = ERROR_ACCESS_DENIED;
+ break;
+ case G_FILE_ERROR_NAMETOOLONG:
+ error = ERROR_FILENAME_EXCED_RANGE;
+ break;
+ case G_FILE_ERROR_NOENT:
+ error = ERROR_FILE_NOT_FOUND;
+ break;
+ case G_FILE_ERROR_NOTDIR:
+ error = ERROR_FILE_NOT_FOUND;
+ break;
+ case G_FILE_ERROR_ROFS:
+ error = ERROR_ACCESS_DENIED;
+ break;
+ case G_FILE_ERROR_TXTBSY:
+ error = ERROR_SHARING_VIOLATION;
+ break;
+ case G_FILE_ERROR_NOSPC:
+ error = ERROR_HANDLE_DISK_FULL;
+ break;
+ case G_FILE_ERROR_NFILE:
+ case G_FILE_ERROR_MFILE:
+ error = ERROR_TOO_MANY_OPEN_FILES;
+ break;
+ case G_FILE_ERROR_BADF:
+ error = ERROR_INVALID_HANDLE;
+ break;
+ case G_FILE_ERROR_INVAL:
+ error = ERROR_INVALID_PARAMETER;
+ break;
+ case G_FILE_ERROR_AGAIN:
+ error = ERROR_SHARING_VIOLATION;
+ break;
+ case G_FILE_ERROR_INTR:
+ error = ERROR_IO_PENDING;
+ break;
+ case G_FILE_ERROR_PERM:
+ error = ERROR_ACCESS_DENIED;
+ break;
+ case G_FILE_ERROR_FAILED:
+ error = ERROR_INVALID_PARAMETER;
+ break;
+ case G_FILE_ERROR_NXIO:
+ case G_FILE_ERROR_NOMEM:
+ case G_FILE_ERROR_NODEV:
+ case G_FILE_ERROR_FAULT:
+ case G_FILE_ERROR_LOOP:
+ case G_FILE_ERROR_PIPE:
+ case G_FILE_ERROR_IO:
+ default:
+ error = ERROR_GEN_FAILURE;
+ break;
+
+ }
+
+ return error;
+}
+
+static gint
+file_compare (gconstpointer a, gconstpointer b)
+{
+ gchar *astr = *(gchar **) a;
+ gchar *bstr = *(gchar **) b;
+
+ return strcmp (astr, bstr);
+}
+
+static gint
+get_file_attributes (const char *filename)
+{
+#ifdef PLATFORM_WIN32
+ gunichar2 *full16;
+ gint result;
+
+ full16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+ if (full16 == NULL) {
+ g_message ("Bad encoding for '%s'\n", filename);
+ return FALSE;
+ }
+
+ result = GetFileAttributes (full16);
+ g_free (full16);
+ return result;
+#else
+ struct stat buf;
+ struct stat linkbuf;
+ int result;
+ int file_attrs;
+
+ result = lstat (filename, &buf);
+ if (result == -1)
+ return FALSE;
+
+ if ((buf.st_mode & S_IFLNK) != 0) {
+ result = stat (filename, &linkbuf);
+ if (result != -1) {
+ buf = linkbuf;
+ } else {
+ buf.st_mode |= ~S_IFDIR; /* force it to be returned as regular file */
+ }
+ }
+
+ file_attrs = 0;
+ if ((buf.st_mode & S_IFDIR) != 0)
+ file_attrs |= FILE_ATTRIBUTE_DIRECTORY;
+ else
+ file_attrs |= FILE_ATTRIBUTE_ARCHIVE;
+
+ if ((buf.st_mode & S_IWUSR) == 0)
+ file_attrs |= FILE_ATTRIBUTE_READONLY;
+
+ if (*filename == '.')
+ file_attrs |= FILE_ATTRIBUTE_HIDDEN;
+
+ return file_attrs;
+#endif
+}
+
+static gboolean
+test_file (const char *filename, int attrs, int mask)
+{
+ int file_attr;
+
+ file_attr = get_file_attributes (filename);
+ if (file_attr == FALSE)
+ return FALSE;
+
+ return ((file_attr & mask) == attrs);
+}
+
+/* scandir using glib */
+static gint
+mono_io_scandir (const gchar *dirname, const gchar *pattern, int attrs,
+ int mask, gchar ***namelist)
+{
+ GError *error = NULL;
+ GDir *dir;
+ GPtrArray *names;
+ const gchar *name;
+ gint result;
+ GPatternSpec *patspec;
+ gchar *full_name;
+
+ mask = convert_attrs (mask);
+ *namelist = NULL;
+ dir = g_dir_open (dirname, 0, &error);
+ if (dir == NULL) {
+ /* g_dir_open returns ENOENT on directories on which we don't
+ * have read/x permission */
+ gint errnum = get_error_from_g_file_error (error->code);
+ g_error_free (error);
+ if (errnum == ERROR_FILE_NOT_FOUND && g_file_test (dirname, G_FILE_TEST_IS_DIR))
+ errnum = ERROR_ACCESS_DENIED;
+
+ SetLastError (errnum);
+ return -1;
+ }
+
+ patspec = g_pattern_spec_new (pattern);
+ names = g_ptr_array_new ();
+ while ((name = g_dir_read_name (dir)) != NULL) {
+ if (!g_pattern_match_string (patspec, name))
+ continue;
+
+ full_name = g_build_filename (dirname, name, NULL);
+ if (FALSE == test_file (full_name, attrs, mask)) {
+ g_free (full_name);
+ continue;
+ }
+
+ g_ptr_array_add (names, full_name);
+ }
- DeleteFile(filename);
+ g_pattern_spec_free (patspec);
+ g_dir_close (dir);
+ result = names->len;
+ if (result > 0) {
+ g_ptr_array_sort (names, file_compare);
+ g_ptr_array_set_size (names, result + 1);
- g_free(filename);
+ *namelist = (gchar **) g_ptr_array_free (names, FALSE);
+ } else {
+ g_ptr_array_free (names, TRUE);
+ }
+
+ return result;
}
-gboolean ves_icall_System_PAL_OpSys_ExistsFile(MonoObject *this, MonoString *path)
+MonoArray *
+ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *_path, MonoString *_pattern,
+ gint attrs, gint mask, gint32 *error)
{
- return(FALSE);
+ MonoDomain *domain;
+ MonoArray *result;
+ gchar **namelist;
+ gchar *path;
+ gchar *pattern;
+ int i, nnames;
+ int removed;
+ MonoString *str_name;
+#ifndef PLATFORM_WIN32
+ gunichar2 *utf16;
+ gsize nbytes;
+#endif
+
+ MONO_ARCH_SAVE_REGS;
+
+ *error = ERROR_SUCCESS;
+
+ path = mono_string_to_utf8 (_path);
+ pattern = mono_string_to_utf8 (_pattern);
+ nnames = mono_io_scandir (path, pattern, attrs, mask, &namelist);
+ if (nnames < 0) {
+ *error = GetLastError ();
+ g_free (pattern);
+ g_free (path);
+ return NULL;
+ }
+
+ domain = mono_domain_get ();
+ result = mono_array_new (domain, mono_defaults.string_class, nnames);
+ removed = 0;
+ for (i = 0; i < nnames; i++) {
+#if PLATFORM_WIN32
+ str_name = mono_string_new (domain, namelist [i]);
+#else
+ utf16 = mono_unicode_from_external (namelist [i], &nbytes);
+ if (utf16 == NULL) {
+ g_message ("Bad encoding for '%s'\nConsider using MONO_EXTERNAL_ENCODING\n",
+ namelist [i]);
+ removed++;
+ continue;
+ }
+ str_name = mono_string_from_utf16 (utf16);
+ g_free (utf16);
+#endif
+ mono_array_set (result, MonoString *, i - removed, str_name);
+ }
+
+ if (removed > 0) {
+ MonoArray *shrinked;
+ shrinked = mono_array_new (domain, mono_defaults.string_class, nnames - removed);
+ for (i = 0; i < (nnames - removed); i++) {
+ MonoString *str;
+ str = mono_array_get (result, MonoString *, i);
+ mono_array_set (shrinked, MonoString *,i, str);
+ }
+ result = shrinked;
+ }
+
+ g_strfreev (namelist);
+ g_free (pattern);
+ g_free (path);
+ return result;
}
-gboolean ves_icall_System_PAL_OpSys_GetFileTime(HANDLE handle, gint64 *createtime, gint64 *lastaccess, gint64 *lastwrite)
+MonoString *
+ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
+{
+ MonoString *result;
+ gunichar2 *buf;
+ int len;
+
+ MONO_ARCH_SAVE_REGS;
+
+ len = MAX_PATH + 1;
+ buf = g_new (gunichar2, len);
+
+ *error=ERROR_SUCCESS;
+ result = NULL;
+
+ if (GetCurrentDirectory (len, buf) > 0) {
+ len = 0;
+ while (buf [len])
+ ++ len;
+
+ result = mono_string_new_utf16 (mono_domain_get (), buf, len);
+ } else {
+ *error=GetLastError ();
+ }
+
+ g_free (buf);
+ return result;
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
+ gint32 *error)
{
gboolean ret;
- FILETIME cr, ac, wr;
- if(handle == INVALID_HANDLE_VALUE)
- mono_raise_exception(mono_get_exception_io("Invalid handle"));
+ MONO_ARCH_SAVE_REGS;
- ret=GetFileTime(handle, &cr, &ac, &wr);
- if(ret==TRUE) {
- /* The FILETIME struct holds two unsigned 32 bit
- * values for the low and high bytes, but the .net
- * file time insists on being signed :(
- */
- *createtime=((gint64)cr.dwHighDateTime << 32) +
- cr.dwLowDateTime;
- *lastaccess=((gint64)ac.dwHighDateTime << 32) +
- ac.dwLowDateTime;
- *lastwrite=((gint64)wr.dwHighDateTime << 32) +
- wr.dwLowDateTime;
+ *error=ERROR_SUCCESS;
+
+ ret=SetCurrentDirectory (mono_string_chars (path));
+ if(ret==FALSE) {
+ *error=GetLastError ();
}
return(ret);
}
-gboolean ves_icall_System_PAL_OpSys_SetFileTime(HANDLE handle, gint64 createtime, gint64 lastaccess, gint64 lastwrite)
+MonoBoolean
+ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
+ gint32 *error)
{
gboolean ret;
- FILETIME cr, ac, wr;
- if(handle == INVALID_HANDLE_VALUE)
- mono_raise_exception(mono_get_exception_io("Invalid handle"));
+ MONO_ARCH_SAVE_REGS;
- cr.dwLowDateTime= createtime & 0xFFFFFFFF;
- cr.dwHighDateTime= createtime >> 32;
+ *error=ERROR_SUCCESS;
+
+ ret=MoveFile (mono_string_chars (path), mono_string_chars (dest));
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
- ac.dwLowDateTime= lastaccess & 0xFFFFFFFF;
- ac.dwHighDateTime= lastaccess >> 32;
+ return(ret);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
+ MonoBoolean overwrite, gint32 *error)
+{
+ gboolean ret;
- wr.dwLowDateTime= lastwrite & 0xFFFFFFFF;
- wr.dwHighDateTime= lastwrite >> 32;
+ MONO_ARCH_SAVE_REGS;
- ret=SetFileTime(handle, &cr, &ac, &wr);
+ *error=ERROR_SUCCESS;
+
+ ret=CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
return(ret);
}
-/* System.IO.FileStream */
+MonoBoolean
+ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
+{
+ gboolean ret;
+
+ MONO_ARCH_SAVE_REGS;
-HANDLE
-ves_icall_System_IO_FileStream_FileOpen (MonoString *path, gint32 mode, gint32 access, gint32 share) {
- HANDLE handle;
- char *filename;
+ *error=ERROR_SUCCESS;
- filename=mono_string_to_utf16(path);
+ ret=DeleteFile (mono_string_chars (path));
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
- handle=CreateFile(filename, convert_access(access),
- convert_share(share), NULL, convert_mode(mode),
- FILE_ATTRIBUTE_NORMAL, NULL);
+ return(ret);
+}
- g_free(filename);
+gint32
+ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
+{
+ gint32 ret;
- /* fixme: raise mor appropriate exceptions (errno) */
- if(handle == INVALID_HANDLE_VALUE) {
- mono_raise_exception(mono_get_exception_io("Invalid handle"));
- }
+ MONO_ARCH_SAVE_REGS;
- return(handle);
-}
+ *error=ERROR_SUCCESS;
+
+ ret=GetFileAttributes (mono_string_chars (path));
-void
-ves_icall_System_IO_FileStream_FileClose (HANDLE handle) {
- if(handle == INVALID_HANDLE_VALUE) {
- mono_raise_exception(mono_get_exception_io("Invalid handle"));
+ /*
+ * The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
+ * headers is wrong, hence this temporary workaround.
+ * See
+ * http://cygwin.com/ml/cygwin/2003-09/msg01771.html
+ */
+ if (ret==-1) {
+ /* if(ret==INVALID_FILE_ATTRIBUTES) { */
+ *error=GetLastError ();
}
+
+ return(ret);
+}
- CloseHandle(handle);
+MonoBoolean
+ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
+ gint32 *error)
+{
+ gboolean ret;
+
+ MONO_ARCH_SAVE_REGS;
+
+ *error=ERROR_SUCCESS;
+
+ ret=SetFileAttributes (mono_string_chars (path),
+ convert_attrs (attrs));
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ return(ret);
}
-gint32
-ves_icall_System_IO_FileStream_FileRead (HANDLE handle, MonoArray *dest, gint32 dest_offset, gint32 count) {
+gint32
+ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
+{
gboolean ret;
- guint32 bytesread;
- guchar *buf;
- gint32 alen;
+
+ MONO_ARCH_SAVE_REGS;
- if(handle == INVALID_HANDLE_VALUE) {
- mono_raise_exception(mono_get_exception_io("Invalid handle"));
+ *error=ERROR_SUCCESS;
+
+ ret=GetFileType (handle);
+ if(ret==FILE_TYPE_UNKNOWN) {
+ /* Not necessarily an error, but the caller will have
+ * to decide based on the error value.
+ */
+ *error=GetLastError ();
}
+
+ return(ret);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
+ gint32 *error)
+{
+ gboolean result;
+ WIN32_FILE_ATTRIBUTE_DATA data;
+
+ MONO_ARCH_SAVE_REGS;
+
+ *error=ERROR_SUCCESS;
+
+ result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
- alen=mono_array_length(dest);
- if(dest_offset+count>alen) {
- return(0);
+ if (result) {
+ convert_win32_file_attribute_data (&data,
+ mono_string_chars (path),
+ stat);
+ } else {
+ *error=GetLastError ();
}
+
+ return result;
+}
+
+HANDLE
+ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
+ gint32 access_mode, gint32 share,
+ MonoBoolean async, gint32 *error)
+{
+ HANDLE ret;
- buf=mono_array_addr(dest, guchar, dest_offset);
+ MONO_ARCH_SAVE_REGS;
+
+ *error=ERROR_SUCCESS;
- ret=ReadFile(handle, buf, count, &bytesread, NULL);
+ ret=CreateFile (mono_string_chars (filename),
+ convert_access (access_mode), convert_share (share),
+ NULL, convert_mode (mode),
+ FILE_ATTRIBUTE_NORMAL | ((async) ? FILE_FLAG_OVERLAPPED : 0),
+ NULL);
+ if(ret==INVALID_HANDLE_VALUE) {
+ *error=GetLastError ();
+ }
- return(bytesread);
+ return(ret);
}
-gint32
-ves_icall_System_IO_FileStream_FileWrite (HANDLE handle, MonoArray *src, gint32 src_offset, gint32 count) {
+MonoBoolean
+ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
+{
gboolean ret;
- guint32 byteswritten;
- guchar *buf;
- gint32 alen;
- if(handle == INVALID_HANDLE_VALUE) {
- mono_raise_exception(mono_get_exception_io("Invalid handle"));
- }
+ MONO_ARCH_SAVE_REGS;
- alen=mono_array_length(src);
- if(src_offset+count>alen) {
- return(0);
+ *error=ERROR_SUCCESS;
+
+ ret=CloseHandle (handle);
+ if(ret==FALSE) {
+ *error=GetLastError ();
}
- buf=mono_array_addr(src, guchar, src_offset);
+ return(ret);
+}
+
+gint32
+ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
+ gint32 dest_offset, gint32 count,
+ gint32 *error)
+{
+ guchar *buffer;
+ gboolean result;
+ guint32 n;
+
+ MONO_ARCH_SAVE_REGS;
+
+ *error=ERROR_SUCCESS;
+
+ if (dest_offset + count > mono_array_length (dest))
+ return 0;
+
+ buffer = mono_array_addr (dest, guchar, dest_offset);
+ result = ReadFile (handle, buffer, count, &n, NULL);
+
+ if (!result) {
+ *error=GetLastError ();
+ return -1;
+ }
+
+ return (gint32)n;
+}
+
+gint32
+ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
+ gint32 src_offset, gint32 count,
+ gint32 *error)
+{
+ guchar *buffer;
+ gboolean result;
+ guint32 n;
+
+ MONO_ARCH_SAVE_REGS;
+
+ *error=ERROR_SUCCESS;
- ret=WriteFile(handle, buf, count, &byteswritten, NULL);
+ if (src_offset + count > mono_array_length (src))
+ return 0;
- return(byteswritten);
+ buffer = mono_array_addr (src, guchar, src_offset);
+ result = WriteFile (handle, buffer, count, &n, NULL);
+
+ if (!result) {
+ *error=GetLastError ();
+ return -1;
+ }
+
+ return (gint32)n;
}
gint64
-ves_icall_System_IO_FileStream_FileSeek (HANDLE handle, gint64 offset, gint32 origin) {
- gint64 ret;
- gint32 offsetlo, offsethi, retlo;
+ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
+ gint32 *error)
+{
+ guint32 offset_hi;
+
+ MONO_ARCH_SAVE_REGS;
+
+ *error=ERROR_SUCCESS;
- if(handle == INVALID_HANDLE_VALUE) {
- mono_raise_exception(mono_get_exception_io("Invalid handle"));
- }
+ offset_hi = offset >> 32;
+ offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
+ convert_seekorigin (origin));
- offsetlo=offset & 0xFFFFFFFF;
- offsethi=offset >> 32;
+ if(offset==INVALID_SET_FILE_POINTER) {
+ *error=GetLastError ();
+ }
+
+ return offset | ((gint64)offset_hi << 32);
+}
- retlo=SetFilePointer(handle, offset, &offsethi,
- convert_seekorigin(origin));
+MonoBoolean
+ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
+{
+ gboolean ret;
- ret=((gint64)offsethi << 32) + retlo;
+ MONO_ARCH_SAVE_REGS;
+ *error=ERROR_SUCCESS;
+
+ ret=FlushFileBuffers (handle);
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
return(ret);
}
gint64
-ves_icall_System_IO_FileStream_FileGetLength (HANDLE handle) {
- gint32 length_lo, length_hi;
+ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
+{
+ gint64 length;
+ guint32 length_hi;
- if (handle == INVALID_HANDLE_VALUE)
- mono_raise_exception (mono_get_exception_io ("Invalid handle"));
+ MONO_ARCH_SAVE_REGS;
+
+ *error=ERROR_SUCCESS;
- length_lo = GetFileSize (handle, &length_hi);
+ length = GetFileSize (handle, &length_hi);
+ if(length==INVALID_FILE_SIZE) {
+ *error=GetLastError ();
+ }
- return ((gint64)length_hi << 32) | length_lo;
+ return length | ((gint64)length_hi << 32);
}
-void
-ves_icall_System_IO_FileStream_FileSetLength (HANDLE handle, gint64 length)
+MonoBoolean
+ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
+ gint32 *error)
{
+ gint64 offset, offset_set;
+ gint32 offset_hi;
+ gint32 length_hi;
gboolean result;
- gint32 position_lo, position_hi;
- gint32 length_lo, length_hi;
- if (handle == INVALID_HANDLE_VALUE)
- mono_raise_exception (mono_get_exception_io ("Invalid handle"));
+ MONO_ARCH_SAVE_REGS;
+ *error=ERROR_SUCCESS;
+
/* save file pointer */
- position_hi = 0;
- position_lo = SetFilePointer (handle, 0, &position_hi, FILE_CURRENT);
+ offset_hi = 0;
+ offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
+ if(offset==INVALID_SET_FILE_POINTER) {
+ *error=GetLastError ();
+ return(FALSE);
+ }
/* extend or truncate */
length_hi = length >> 32;
- length_lo = length & 0xFFFFFFFF;
+ offset_set=SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi,
+ FILE_BEGIN);
+ if(offset_set==INVALID_SET_FILE_POINTER) {
+ *error=GetLastError ();
+ return(FALSE);
+ }
- SetFilePointer (handle, length_lo, &length_hi, FILE_BEGIN);
result = SetEndOfFile (handle);
+ if(result==FALSE) {
+ *error=GetLastError ();
+ return(FALSE);
+ }
+
+ /* restore file pointer */
+
+ offset_set=SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
+ FILE_BEGIN);
+ if(offset_set==INVALID_SET_FILE_POINTER) {
+ *error=GetLastError ();
+ return(FALSE);
+ }
+
+ return result;
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
+ gint64 last_access_time,
+ gint64 last_write_time, gint32 *error)
+{
+ gboolean ret;
+ const FILETIME *creation_filetime;
+ const FILETIME *last_access_filetime;
+ const FILETIME *last_write_filetime;
- /* restore */
+ MONO_ARCH_SAVE_REGS;
- SetFilePointer (handle, position_lo, &position_hi, FILE_BEGIN);
+ *error=ERROR_SUCCESS;
- if (result == FALSE)
- mono_raise_exception (mono_get_exception_io ("IO Exception"));
+ if (creation_time < 0)
+ creation_filetime = NULL;
+ else
+ creation_filetime = (FILETIME *)&creation_time;
+
+ if (last_access_time < 0)
+ last_access_filetime = NULL;
+ else
+ last_access_filetime = (FILETIME *)&last_access_time;
+
+ if (last_write_time < 0)
+ last_write_filetime = NULL;
+ else
+ last_write_filetime = (FILETIME *)&last_write_time;
+
+ ret=SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
+ if(ret==FALSE) {
+ *error=GetLastError ();
+ }
+
+ return(ret);
}
-void
-ves_icall_System_IO_FileStream_FileFlush (HANDLE handle)
+HANDLE
+ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
{
- gboolean result;
+ MONO_ARCH_SAVE_REGS;
+
+ return GetStdHandle (STD_OUTPUT_HANDLE);
+}
+
+HANDLE
+ves_icall_System_IO_MonoIO_get_ConsoleInput ()
+{
+ MONO_ARCH_SAVE_REGS;
+
+ return GetStdHandle (STD_INPUT_HANDLE);
+}
+
+HANDLE
+ves_icall_System_IO_MonoIO_get_ConsoleError ()
+{
+ MONO_ARCH_SAVE_REGS;
+
+ return GetStdHandle (STD_ERROR_HANDLE);
+}
+
+MonoBoolean
+ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
+ HANDLE *write_handle)
+{
+ SECURITY_ATTRIBUTES attr;
+ gboolean ret;
+
+ MONO_ARCH_SAVE_REGS;
+
+ attr.nLength=sizeof(SECURITY_ATTRIBUTES);
+ attr.bInheritHandle=TRUE;
+ attr.lpSecurityDescriptor=NULL;
+
+ ret=CreatePipe (read_handle, write_handle, &attr, 0);
+ if(ret==FALSE) {
+ /* FIXME: throw an exception? */
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
+{
+#if defined (PLATFORM_WIN32)
+ return (gunichar2) ':'; /* colon */
+#else
+ return (gunichar2) '/'; /* forward slash */
+#endif
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
+{
+#if defined (PLATFORM_WIN32)
+ return (gunichar2) '\\'; /* backslash */
+#else
+ return (gunichar2) '/'; /* forward slash */
+#endif
+}
+
+gunichar2
+ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
+{
+#if defined (PLATFORM_WIN32)
+ return (gunichar2) '/'; /* forward slash */
+#else
+ return (gunichar2) '/'; /* slash, same as DirectorySeparatorChar */
+#endif
+}
- if (handle == INVALID_HANDLE_VALUE)
- mono_raise_exception (mono_get_exception_io ("Invalid handle"));
+gunichar2
+ves_icall_System_IO_MonoIO_get_PathSeparator ()
+{
+#if defined (PLATFORM_WIN32)
+ return (gunichar2) ';'; /* semicolon */
+#else
+ return (gunichar2) ':'; /* colon */
+#endif
+}
+
+static const gunichar2
+invalid_path_chars [] = {
+#if defined (PLATFORM_WIN32)
+ 0x0022, /* double quote, which seems allowed in MS.NET but should be rejected */
+ 0x003c, /* less than */
+ 0x003e, /* greater than */
+ 0x007c, /* pipe */
+ 0x0008,
+ 0x0010,
+ 0x0011,
+ 0x0012,
+ 0x0014,
+ 0x0015,
+ 0x0016,
+ 0x0017,
+ 0x0018,
+ 0x0019,
+#endif
+ 0x0000 /* null */
+};
+
+MonoArray *
+ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
+{
+ MonoArray *chars;
+ MonoDomain *domain;
+ int i, n;
- FlushFileBuffers (handle); /* discard result */
+ MONO_ARCH_SAVE_REGS;
+
+ domain = mono_domain_get ();
+ n = sizeof (invalid_path_chars) / sizeof (gunichar2);
+ chars = mono_array_new (domain, mono_defaults.char_class, n);
+
+ for (i = 0; i < n; ++ i)
+ mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
+
+ return chars;
}
+
+gint32
+ves_icall_System_IO_MonoIO_GetTempPath (MonoString **mono_name)
+{
+ gunichar2 *name;
+ int ret;
+
+ name=g_new0 (gunichar2, 256);
+
+ ret=GetTempPath (256, name);
+ if(ret>255) {
+ /* Buffer was too short. Try again... */
+ g_free (name);
+ name=g_new0 (gunichar2, ret+2); /* include the terminator */
+ ret=GetTempPath (ret, name);
+ }
+
+ if(ret>0) {
+#ifdef DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION
+ ": Temp path is [%s] (len %d)", name, ret);
+#endif
+
+ *mono_name=mono_string_new_utf16 (mono_domain_get (), name,
+ ret);
+ }
+
+ g_free (name);
+
+ return(ret);
+}
+
+void ves_icall_System_IO_MonoIO_Lock (HANDLE handle, gint64 position,
+ gint64 length, gint32 *error)
+{
+ gboolean ret;
+
+ *error=ERROR_SUCCESS;
+
+ ret=LockFile (handle, position & 0xFFFFFFFF, position >> 32,
+ length & 0xFFFFFFFF, length >> 32);
+ if (ret == FALSE) {
+ *error = GetLastError ();
+ }
+}
+
+void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
+ gint64 length, gint32 *error)
+{
+ gboolean ret;
+
+ *error=ERROR_SUCCESS;
+
+ ret=UnlockFile (handle, position & 0xFFFFFFFF, position >> 32,
+ length & 0xFFFFFFFF, length >> 32);
+ if (ret == FALSE) {
+ *error = GetLastError ();
+ }
+}
+