*
* 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 <errno.h>
#include <signal.h>
#include <unistd.h>
-
-#ifndef PLATFORM_WIN32
-#ifdef HAVE_AIO_H
-#include <aio.h>
-#define USE_AIO 1
-#elif defined(HAVE_SYS_AIO_H)
-#include <sys/aio.h>
-#define USE_AIO 1
-#else
-#undef USE_AIO
+#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/metadata/exception.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/marshal.h>
+#include <mono/utils/strenc.h>
#undef DEBUG
return(ret);
}
-HANDLE
-ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat,
- gint32 *error)
+static gint
+get_error_from_g_file_error (gint error)
{
- WIN32_FIND_DATA data;
- HANDLE result;
+ 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;
- MONO_ARCH_SAVE_REGS;
+ }
- *error=ERROR_SUCCESS;
-
- result = FindFirstFile (mono_string_chars (path), &data);
+ return error;
+}
- /* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
+static gint
+file_compare (gconstpointer a, gconstpointer b)
+{
+ gchar *astr = *(gchar **) a;
+ gchar *bstr = *(gchar **) b;
- if (result != INVALID_HANDLE_VALUE) {
- convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
- &data.cFileName [0], stat);
- } else {
- *error=GetLastError ();
+ 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
}
-MonoBoolean
-ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat,
- gint32 *error)
+static gboolean
+test_file (const char *filename, int attrs, int mask)
{
- WIN32_FIND_DATA data;
- gboolean result;
+ int file_attr;
- MONO_ARCH_SAVE_REGS;
+ file_attr = get_file_attributes (filename);
+ if (file_attr == FALSE)
+ return FALSE;
- *error=ERROR_SUCCESS;
+ 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);
+ }
- result = FindNextFile (find, &data);
- if (result) {
- convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
- &data.cFileName [0], stat);
+ 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);
+
+ *namelist = (gchar **) g_ptr_array_free (names, FALSE);
} else {
- *error=GetLastError ();
+ g_ptr_array_free (names, TRUE);
}
return result;
}
-MonoBoolean
-ves_icall_System_IO_MonoIO_FindClose (HANDLE find, gint32 *error)
+MonoArray *
+ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *_path, MonoString *_pattern,
+ gint attrs, gint mask, gint32 *error)
{
- gboolean ret;
-
+ 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;
-
- ret=FindClose (find);
- if(ret==FALSE) {
- *error=GetLastError ();
+ *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;
}
-
- return(ret);
+
+ 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;
}
MonoString *
* http://cygwin.com/ml/cygwin/2003-09/msg01771.html
*/
if (ret==-1) {
-// if(ret==INVALID_FILE_ATTRIBUTES) {
+ /* if(ret==INVALID_FILE_ATTRIBUTES) { */
*error=GetLastError ();
}
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, which seems allowed in MS.NET but should be rejected */
0x003c, /* less than */
MONO_ARCH_SAVE_REGS;
domain = mono_domain_get ();
- chars = mono_array_new (domain, mono_defaults.char_class, 15);
-
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(ret);
}
-/*
- * Asynchronous IO
- */
-MonoBoolean
-ves_icall_System_IO_MonoIO_GetSupportsAsync (void)
-{
- MONO_ARCH_SAVE_REGS;
-
-#ifdef PLATFORM_WIN32
- /* Seems like BindIoCompletionCallback is not found when compiling...
- * Disabling AIO support on win. Any one wants to fix this?
- */
- return FALSE;
- /* return (g_getenv ("MONO_DISABLE_AIO") == NULL && WINVER >= 0x500); */
-#elif defined(USE_AIO)
- if (aio_cancel (-1, NULL) == -1 && errno == ENOSYS)
- return FALSE;
-
- return (g_getenv ("MONO_DISABLE_AIO") == NULL);
-#else
- return FALSE;
-#endif
-}
-
-static WapiOverlapped *
-get_overlapped_from_fsa (MonoFSAsyncResult *ares)
-{
- WapiOverlapped *ovl;
-
- ovl = g_new0 (WapiOverlapped, 1);
- ovl->Offset = ares->offset;
- ovl->hEvent = ares->wait_handle;
-
- return ovl;
-}
-
-MonoBoolean
-ves_icall_System_IO_MonoIO_BeginRead (HANDLE handle, MonoFSAsyncResult *ares)
+void ves_icall_System_IO_MonoIO_Lock (HANDLE handle, gint64 position,
+ gint64 length, gint32 *error)
{
- guint32 bytesread;
- WapiOverlapped *ovl;
-
- MONO_ARCH_SAVE_REGS;
-
- ovl = get_overlapped_from_fsa (ares);
- ovl->handle1 = ares;
- return ReadFile (handle, mono_array_addr (ares->buffer, gchar, ares->offset), ares->count, &bytesread, ovl);
+ gboolean ret;
+
+ *error=ERROR_SUCCESS;
+
+ ret=LockFile (handle, position & 0xFFFFFFFF, position >> 32,
+ length & 0xFFFFFFFF, length >> 32);
+ if (ret == FALSE) {
+ *error = GetLastError ();
+ }
}
-MonoBoolean
-ves_icall_System_IO_MonoIO_BeginWrite (HANDLE handle, MonoFSAsyncResult *ares)
+void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
+ gint64 length, gint32 *error)
{
- guint32 byteswritten;
- WapiOverlapped *ovl;
-
- MONO_ARCH_SAVE_REGS;
-
- ovl = get_overlapped_from_fsa (ares);
- ovl->handle1 = ares;
- return WriteFile (handle, mono_array_addr (ares->buffer, gchar, ares->offset), ares->count, &byteswritten, ovl);
+ gboolean ret;
+
+ *error=ERROR_SUCCESS;
+
+ ret=UnlockFile (handle, position & 0xFFFFFFFF, position >> 32,
+ length & 0xFFFFFFFF, length >> 32);
+ if (ret == FALSE) {
+ *error = GetLastError ();
+ }
}