#include <config.h>
#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
#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>
#undef DEBUG
static gint64 convert_filetime (const FILETIME *filetime)
{
- gint64 *ticks;
-
- ticks = (gint64 *)filetime;
- return *ticks;
+ 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)
stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
}
+/* 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;
+ }
+
+ return(attrs);
+}
+
/* System.IO.MonoIO internal calls */
MonoBoolean
ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=CreateDirectory (mono_string_chars (path), NULL);
MonoBoolean
ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=RemoveDirectory (mono_string_chars (path));
ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
WIN32_FIND_DATA data;
HANDLE result;
+ gboolean r = TRUE;
+
+ MONO_ARCH_SAVE_REGS;
*error=ERROR_SUCCESS;
-
+
result = FindFirstFile (mono_string_chars (path), &data);
/* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
-
- if (result != INVALID_HANDLE_VALUE) {
- convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
- &data.cFileName [0], stat);
- } else {
+ while (result != INVALID_HANDLE_VALUE && r) {
+ if ((data.cFileName [0] == '.' && data.cFileName [1] == 0) ||
+ (data.cFileName [0] == '.' && data.cFileName [1] == '.' && data.cFileName [2] == 0)) {
+ r = FindNextFile (result, &data);
+ } else {
+ convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
+ &data.cFileName [0], stat);
+ break;
+ }
+ }
+
+ if (result == INVALID_HANDLE_VALUE) {
*error=GetLastError ();
}
+
+ if (r == FALSE) {
+ /* No more files were found, after we discarded . and .. */
+ FindClose(result);
+ result = INVALID_HANDLE_VALUE;
+ *error = ERROR_NO_MORE_FILES;
+ }
return result;
}
ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
WIN32_FIND_DATA data;
gboolean result;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
result = FindNextFile (find, &data);
- if (result) {
- convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
- &data.cFileName [0], stat);
- } else {
+ while (result != FALSE) {
+ if ((data.cFileName [0] == '.' && data.cFileName [1] == 0) ||
+ (data.cFileName [0] == '.' && data.cFileName [1] == '.' && data.cFileName [2] == 0)) {
+ result = FindNextFile (find, &data);
+ } else {
+ convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
+ &data.cFileName [0], stat);
+ break;
+ }
+ }
+
+ if (result == FALSE) {
*error=GetLastError ();
}
MonoBoolean
ves_icall_System_IO_MonoIO_FindClose (HANDLE find, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=FindClose (find);
MonoString *
ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
MonoString *result;
gunichar2 *buf;
int len;
+ MONO_ARCH_SAVE_REGS;
+
len = MAX_PATH + 1;
buf = g_new (gunichar2, len);
ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=SetCurrentDirectory (mono_string_chars (path));
ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=MoveFile (mono_string_chars (path), mono_string_chars (dest));
ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
MonoBoolean overwrite, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
MonoBoolean
ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=DeleteFile (mono_string_chars (path));
gint32
ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gint32 ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=GetFileAttributes (mono_string_chars (path));
- if(ret==INVALID_FILE_ATTRIBUTES) {
+
+ /*
+ * 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 ();
}
ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
- ret=SetFileAttributes (mono_string_chars (path), attrs);
+ ret=SetFileAttributes (mono_string_chars (path),
+ convert_attrs (attrs));
if(ret==FALSE) {
*error=GetLastError ();
}
gint32
ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=GetFileType (handle);
ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean result;
WIN32_FILE_ATTRIBUTE_DATA data;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
HANDLE
ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
gint32 access_mode, gint32 share,
- gint32 *error)
+ MonoBoolean async, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
HANDLE ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=CreateFile (mono_string_chars (filename),
convert_access (access_mode), convert_share (share),
- NULL, convert_mode (mode), FILE_ATTRIBUTE_NORMAL,
+ NULL, convert_mode (mode),
+ FILE_ATTRIBUTE_NORMAL | ((async) ? FILE_FLAG_OVERLAPPED : 0),
NULL);
if(ret==INVALID_HANDLE_VALUE) {
*error=GetLastError ();
MonoBoolean
ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=CloseHandle (handle);
gint32 dest_offset, gint32 count,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
guchar *buffer;
gboolean result;
guint32 n;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
if (dest_offset + count > mono_array_length (dest))
gint32 src_offset, gint32 count,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
guchar *buffer;
gboolean result;
guint32 n;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
if (src_offset + count > mono_array_length (src))
ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
guint32 offset_hi;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
offset_hi = offset >> 32;
MonoBoolean
ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
ret=FlushFileBuffers (handle);
gint64
ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gint64 length;
guint32 length_hi;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
length = GetFileSize (handle, &length_hi);
ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gint64 offset, offset_set;
gint32 offset_hi;
gint32 length_hi;
gboolean result;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
/* save file pointer */
gint64 last_access_time,
gint64 last_write_time, gint32 *error)
{
- MONO_ARCH_SAVE_REGS;
-
gboolean ret;
const FILETIME *creation_filetime;
const FILETIME *last_access_filetime;
const FILETIME *last_write_filetime;
+ MONO_ARCH_SAVE_REGS;
+
*error=ERROR_SUCCESS;
if (creation_time < 0)
ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
HANDLE *write_handle)
{
- MONO_ARCH_SAVE_REGS;
-
SECURITY_ATTRIBUTES attr;
gboolean ret;
+ MONO_ARCH_SAVE_REGS;
+
attr.nLength=sizeof(SECURITY_ATTRIBUTES);
attr.bInheritHandle=TRUE;
attr.lpSecurityDescriptor=NULL;
gunichar2
ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
{
- MONO_ARCH_SAVE_REGS;
-
#if defined (PLATFORM_WIN32)
- return (gunichar2) 0x003a; /* colon */
+ return (gunichar2) ':'; /* colon */
#else
- return (gunichar2) 0x002f; /* forward slash */
+ return (gunichar2) '/'; /* forward slash */
#endif
}
gunichar2
ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
{
- MONO_ARCH_SAVE_REGS;
-
#if defined (PLATFORM_WIN32)
- return (gunichar2) 0x005c; /* backslash */
+ return (gunichar2) '\\'; /* backslash */
#else
- return (gunichar2) 0x002f; /* forward slash */
+ return (gunichar2) '/'; /* forward slash */
#endif
}
gunichar2
ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
{
- MONO_ARCH_SAVE_REGS;
-
#if defined (PLATFORM_WIN32)
- return (gunichar2) 0x002f; /* forward slash */
+ return (gunichar2) '/'; /* forward slash */
#else
- return (gunichar2) 0x005c; /* backslash */
+ return (gunichar2) '/'; /* slash, same as DirectorySeparatorChar */
#endif
}
gunichar2
ves_icall_System_IO_MonoIO_get_PathSeparator ()
{
- MONO_ARCH_SAVE_REGS;
-
#if defined (PLATFORM_WIN32)
- return (gunichar2) 0x003b; /* semicolon */
+ return (gunichar2) ';'; /* semicolon */
#else
- return (gunichar2) 0x003a; /* colon */
+ return (gunichar2) ':'; /* colon */
#endif
}
-static gunichar2 invalid_path_chars [] = {
+static const gunichar2
+invalid_path_chars [] = {
#if defined (PLATFORM_WIN32)
- 0x0022, /* double quote */
+ 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 ()
{
- MONO_ARCH_SAVE_REGS;
-
MonoArray *chars;
MonoDomain *domain;
int i, n;
- domain = mono_domain_get ();
- chars = mono_array_new (domain, mono_defaults.char_class, 5);
+ 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 ();
+ }
+}
+