* 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)
+ * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
*/
#include <config.h>
#include <glib.h>
#include <string.h>
#include <errno.h>
-#include <signal.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <mono/metadata/appdomain.h>
#include <mono/metadata/marshal.h>
#include <mono/utils/strenc.h>
+#include <utils/mono-io-portability.h>
#undef DEBUG
return (gint64)ticks;
}
-static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
+static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, MonoIOStat *stat)
{
- 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);
}
/* Managed file attributes have nearly but not quite the same values
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,
HANDLE find_handle;
GPtrArray *names;
gchar *utf8_path, *utf8_result, *full_name;
+ gint32 attributes;
MONO_ARCH_SAVE_REGS;
+ result = NULL;
*error = ERROR_SUCCESS;
domain = mono_domain_get ();
mask = convert_attrs (mask);
+ attributes = get_file_attributes (mono_string_chars (path));
+ if (attributes != -1) {
+ if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
+ *error = ERROR_INVALID_NAME;
+ goto leave;
+ }
+ } else {
+ *error = GetLastError ();
+ goto leave;
+ }
- find_handle = FindFirstFile (mono_string_chars (path_with_pattern),
- &data);
+ find_handle = FindFirstFile (mono_string_chars (path_with_pattern), &data);
if (find_handle == INVALID_HANDLE_VALUE) {
gint32 find_error = GetLastError ();
- if (find_error == ERROR_FILE_NOT_FOUND) {
+ if (find_error == ERROR_FILE_NOT_FOUND || find_error == ERROR_NO_MORE_FILES) {
/* No files, so just return an empty array */
- result = mono_array_new (domain,
- mono_defaults.string_class,
- 0);
-
- return(result);
+ goto leave;
}
*error = find_error;
- return(NULL);
+ goto leave;
}
+ 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) ||
}
g_ptr_array_free (names, TRUE);
g_free (utf8_path);
+
+leave:
+ // If there's no array and no error, then return an empty array.
+ if (result == NULL && *error == ERROR_SUCCESS)
+ result = mono_array_new (domain, mono_defaults.string_class, 0);
+
+ 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)
{
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);
+ res_len = GetCurrentDirectory (res_len, buf) == old_res_len;
}
if (res_len) {
result = get_file_attributes_ex (mono_string_chars (path), &data);
if (result) {
- convert_win32_file_attribute_data (&data,
- mono_string_chars (path),
- stat);
+ convert_win32_file_attribute_data (&data, stat);
} else {
*error=GetLastError ();
+ memset (stat, 0, sizeof (MonoIOStat));
}
return result;
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) {
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 */
+ if (IS_PORTABILITY_SET)
+ return (gunichar2) '\\'; /* backslash */
+ else
+ return (gunichar2) '/'; /* forward slash */
#endif
}
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);
}
}
+//Support for io-layer free mmap'd files.
+
+#if defined (TARGET_IOS) || defined (TARGET_ANDROID)
+
+gint64
+mono_filesize_from_path (MonoString *string)
+{
+ struct stat buf;
+ gint64 res;
+ char *path = mono_string_to_utf8 (string);
+
+ if (stat (path, &buf) == -1)
+ res = -1;
+ else
+ res = (gint64)buf.st_size;
+
+ g_free (path);
+ return res;
+}
+
+gint64
+mono_filesize_from_fd (int fd)
+{
+ struct stat buf;
+
+ if (fstat (fd, &buf) == -1)
+ return (gint64)-1;
+
+ return (gint64)buf.st_size;
+}
+
+#endif