* Dick Porter (dick@ximian.com)
* Gonzalo Paniagua Javier (gonzalo@ximian.com)
*
- * (C) 2001,2002,2003 Ximian, Inc.
- * Copyright (c) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
*/
#include <config.h>
+
#include <glib.h>
#include <string.h>
#include <errno.h>
-#include <signal.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
while (name [len])
++ len;
- stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
+ MONO_STRUCT_SETREF (stat, name, mono_string_new_utf16 (mono_domain_get (), name, len));
}
/* Managed file attributes have nearly but not quite the same values
return(attrs);
}
+/*
+ * On Win32, GetFileAttributes|Ex () seems to try opening the file,
+ * which might lead to sharing violation errors, whereas FindFirstFile
+ * always succeeds. These 2 wrappers resort to FindFirstFile if
+ * GetFileAttributes|Ex () has failed.
+ */
+static guint32
+get_file_attributes (const gunichar2 *path)
+{
+ guint32 res;
+ WIN32_FIND_DATA find_data;
+ HANDLE find_handle;
+ gint32 error;
+
+ res = GetFileAttributes (path);
+ if (res != -1)
+ return res;
+
+ error = GetLastError ();
+
+ if (error != ERROR_SHARING_VIOLATION)
+ return res;
+
+ find_handle = FindFirstFile (path, &find_data);
+
+ if (find_handle == INVALID_HANDLE_VALUE)
+ return res;
+
+ FindClose (find_handle);
+
+ return find_data.dwFileAttributes;
+}
+
+static gboolean
+get_file_attributes_ex (const gunichar2 *path, WIN32_FILE_ATTRIBUTE_DATA *data)
+{
+ gboolean res;
+ WIN32_FIND_DATA find_data;
+ HANDLE find_handle;
+ gint32 error;
+
+ res = GetFileAttributesEx (path, GetFileExInfoStandard, data);
+ if (res)
+ return TRUE;
+
+ error = GetLastError ();
+
+ if (error != ERROR_SHARING_VIOLATION)
+ return FALSE;
+
+ find_handle = FindFirstFile (path, &find_data);
+
+ if (find_handle == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ FindClose (find_handle);
+
+ data->dwFileAttributes = find_data.dwFileAttributes;
+ data->ftCreationTime = find_data.ftCreationTime;
+ data->ftLastAccessTime = find_data.ftLastAccessTime;
+ data->ftLastWriteTime = find_data.ftLastWriteTime;
+ data->nFileSizeHigh = find_data.nFileSizeHigh;
+ data->nFileSizeLow = find_data.nFileSizeLow;
+
+ return TRUE;
+}
+
/* System.IO.MonoIO internal calls */
MonoBoolean
return(ret);
}
+static gchar *
+get_search_dir (MonoString *pattern)
+{
+ gchar *p;
+ gchar *result;
+
+ p = mono_string_to_utf8 (pattern);
+ result = g_path_get_dirname (p);
+ g_free (p);
+ return result;
+}
+
MonoArray *
ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
MonoString *path_with_pattern,
return(NULL);
}
+ utf8_path = get_search_dir (path_with_pattern);
names = g_ptr_array_new ();
- utf8_path = mono_string_to_utf8 (path);
do {
if ((data.cFileName[0] == '.' && data.cFileName[1] == 0) ||
if (FindClose (find_handle) == FALSE) {
*error = GetLastError ();
- g_ptr_array_free (names, TRUE);
- g_free (utf8_path);
- return(NULL);
+ result = NULL;
+ } else {
+ result = mono_array_new (domain, mono_defaults.string_class, names->len);
+ for (i = 0; i < names->len; i++) {
+ mono_array_setref (result, i, mono_string_new (domain, g_ptr_array_index (names, i)));
+ }
}
- result = mono_array_new (domain, mono_defaults.string_class,
- names->len);
for (i = 0; i < names->len; i++) {
- mono_array_setref (result, i, mono_string_new (domain, g_ptr_array_index (names, i)));
+ g_free (g_ptr_array_index (names, i));
}
-
g_ptr_array_free (names, TRUE);
g_free (utf8_path);
return result;
}
+typedef struct {
+ MonoDomain *domain;
+ gchar *utf8_path;
+ HANDLE find_handle;
+} IncrementalFind;
+
+static gboolean
+incremental_find_check_match (IncrementalFind *handle, WIN32_FIND_DATA *data, MonoString **result)
+{
+ gchar *utf8_result;
+ gchar *full_name;
+
+ if ((data->cFileName[0] == '.' && data->cFileName[1] == 0) || (data->cFileName[0] == '.' && data->cFileName[1] == '.' && data->cFileName[2] == 0))
+ return FALSE;
+
+ utf8_result = g_utf16_to_utf8 (data->cFileName, -1, NULL, NULL, NULL);
+ if (utf8_result == NULL)
+ return FALSE;
+
+ full_name = g_build_filename (handle->utf8_path, utf8_result, NULL);
+ g_free (utf8_result);
+ *result = mono_string_new (mono_domain_get (), full_name);
+ g_free (full_name);
+
+ return TRUE;
+}
+
+MonoString *
+ves_icall_System_IO_MonoIO_FindFirst (MonoString *path,
+ MonoString *path_with_pattern,
+ gint32 *result_attr, gint32 *error,
+ gpointer *handle)
+{
+ WIN32_FIND_DATA data;
+ HANDLE find_handle;
+ IncrementalFind *ifh;
+ MonoString *result;
+
+ *error = ERROR_SUCCESS;
+
+ find_handle = FindFirstFile (mono_string_chars (path_with_pattern), &data);
+
+ if (find_handle == INVALID_HANDLE_VALUE) {
+ gint32 find_error = GetLastError ();
+ *handle = NULL;
+
+ if (find_error == ERROR_FILE_NOT_FOUND)
+ return NULL;
+
+ *error = find_error;
+ return NULL;
+ }
+
+ ifh = g_new (IncrementalFind, 1);
+ ifh->find_handle = find_handle;
+ ifh->utf8_path = mono_string_to_utf8 (path);
+ ifh->domain = mono_domain_get ();
+ *handle = ifh;
+
+ while (incremental_find_check_match (ifh, &data, &result) == 0){
+ if (FindNextFile (find_handle, &data) == FALSE){
+ int e = GetLastError ();
+ if (e != ERROR_NO_MORE_FILES)
+ *error = e;
+ return NULL;
+ }
+ }
+ *result_attr = data.dwFileAttributes;
+
+ return result;
+}
+
+MonoString *
+ves_icall_System_IO_MonoIO_FindNext (gpointer handle, gint32 *result_attr, gint32 *error)
+{
+ IncrementalFind *ifh = handle;
+ WIN32_FIND_DATA data;
+ MonoString *result;
+
+ error = ERROR_SUCCESS;
+ do {
+ if (FindNextFile (ifh->find_handle, &data) == FALSE){
+ int e = GetLastError ();
+ if (e != ERROR_NO_MORE_FILES)
+ *error = e;
+ return NULL;
+ }
+ } while (incremental_find_check_match (ifh, &data, &result) == 0);
+
+ *result_attr = data.dwFileAttributes;
+ return result;
+}
+
+int
+ves_icall_System_IO_MonoIO_FindClose (gpointer handle)
+{
+ IncrementalFind *ifh = handle;
+ gint32 error;
+
+ if (FindClose (ifh->find_handle) == FALSE){
+ error = GetLastError ();
+ } else
+ error = ERROR_SUCCESS;
+ g_free (ifh->utf8_path);
+ g_free (ifh);
+
+ return error;
+}
+
MonoString *
ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
{
MonoString *result;
gunichar2 *buf;
- int len;
+ int len, res_len;
MONO_ARCH_SAVE_REGS;
- len = MAX_PATH + 1;
+ len = MAX_PATH + 1; /*FIXME this is too smal under most unix systems.*/
buf = g_new (gunichar2, len);
*error=ERROR_SUCCESS;
result = NULL;
- if (GetCurrentDirectory (len, buf) > 0) {
+ res_len = GetCurrentDirectory (len, buf);
+ if (res_len > len) { /*buf is too small.*/
+ int old_res_len = res_len;
+ g_free (buf);
+ buf = g_new (gunichar2, res_len);
+ res_len = GetCurrentDirectory (res_len, buf) == old_res_len;
+ }
+
+ if (res_len) {
len = 0;
while (buf [len])
++ len;
return(ret);
}
+MonoBoolean
+ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
+ MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
+ gint32 *error)
+{
+ gboolean ret;
+ gunichar2 *utf16_sourceFileName = NULL, *utf16_destinationFileName = NULL, *utf16_destinationBackupFileName = NULL;
+ guint32 replaceFlags = REPLACEFILE_WRITE_THROUGH;
+
+ MONO_ARCH_SAVE_REGS;
+
+ if (sourceFileName)
+ utf16_sourceFileName = mono_string_chars (sourceFileName);
+ if (destinationFileName)
+ utf16_destinationFileName = mono_string_chars (destinationFileName);
+ if (destinationBackupFileName)
+ utf16_destinationBackupFileName = mono_string_chars (destinationBackupFileName);
+
+ *error = ERROR_SUCCESS;
+ if (ignoreMetadataErrors)
+ replaceFlags |= REPLACEFILE_IGNORE_MERGE_ERRORS;
+
+ ret = ReplaceFile (utf16_destinationFileName, utf16_sourceFileName, utf16_destinationBackupFileName,
+ replaceFlags, NULL, NULL);
+ if (ret == FALSE)
+ *error = GetLastError ();
+
+ return ret;
+}
+
MonoBoolean
ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
MonoBoolean overwrite, gint32 *error)
*error=ERROR_SUCCESS;
- ret=GetFileAttributes (mono_string_chars (path));
+ ret=get_file_attributes (mono_string_chars (path));
/*
* The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
*error=ERROR_SUCCESS;
- result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
+ result = get_file_attributes_ex (mono_string_chars (path), &data);
if (result) {
convert_win32_file_attribute_data (&data,
stat);
} else {
*error=GetLastError ();
+ memset (stat, 0, sizeof (MonoIOStat));
}
return result;
/* If we're opening a directory we need to set the extra flag
*/
- attrs = GetFileAttributes (chars);
+ attrs = get_file_attributes (chars);
if (attrs != INVALID_FILE_ATTRIBUTES) {
if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
MONO_ARCH_SAVE_REGS;
*error=ERROR_SUCCESS;
+
+ MONO_CHECK_ARG_NULL (dest);
if (dest_offset + count > mono_array_length (dest))
return 0;
MONO_ARCH_SAVE_REGS;
*error=ERROR_SUCCESS;
+
+ MONO_CHECK_ARG_NULL (src);
if (src_offset + count > mono_array_length (src))
return 0;
*error=ERROR_SUCCESS;
offset_hi = offset >> 32;
- offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
+ offset = SetFilePointer (handle, (gint32) (offset & 0xFFFFFFFF), &offset_hi,
convert_seekorigin (origin));
if(offset==INVALID_SET_FILE_POINTER) {
return(TRUE);
}
+MonoBoolean ves_icall_System_IO_MonoIO_DuplicateHandle (HANDLE source_process_handle,
+ HANDLE source_handle, HANDLE target_process_handle, HANDLE *target_handle,
+ gint32 access, gint32 inherit, gint32 options)
+{
+ /* This is only used on Windows */
+ gboolean ret;
+
+ MONO_ARCH_SAVE_REGS;
+
+ ret=DuplicateHandle (source_process_handle, source_handle, target_process_handle, target_handle, access, inherit, options);
+ if(ret==FALSE) {
+ /* FIXME: throw an exception? */
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
gunichar2
ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
{
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
return (gunichar2) ':'; /* colon */
#else
return (gunichar2) '/'; /* forward slash */
gunichar2
ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
{
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
return (gunichar2) '\\'; /* backslash */
#else
return (gunichar2) '/'; /* forward slash */
gunichar2
ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
{
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
return (gunichar2) '/'; /* forward slash */
#else
return (gunichar2) '/'; /* slash, same as DirectorySeparatorChar */
gunichar2
ves_icall_System_IO_MonoIO_get_PathSeparator ()
{
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
return (gunichar2) ';'; /* semicolon */
#else
return (gunichar2) ':'; /* colon */
static const gunichar2
invalid_path_chars [] = {
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
0x0022, /* double quote, which seems allowed in MS.NET but should be rejected */
0x003c, /* less than */
0x003e, /* greater than */
if(ret>0) {
#ifdef DEBUG
- g_message (G_GNUC_PRETTY_FUNCTION
- ": Temp path is [%s] (len %d)", name, ret);
+ g_message ("%s: Temp path is [%s] (len %d)", __func__, name, ret);
#endif
- *mono_name=mono_string_new_utf16 (mono_domain_get (), name,
- ret);
+ mono_gc_wbarrier_generic_store ((gpointer) mono_name,
+ (MonoObject*) mono_string_new_utf16 (mono_domain_get (), name, ret));
}
g_free (name);