Merge pull request #101 from occ/master
[mono.git] / mono / io-layer / error.c
index 462df56401698aa508c0ada039942e1ee98493d0..541468d1b3edd00a85abaa905e897af3c3710aa9 100644 (file)
@@ -1,15 +1,38 @@
+/*
+ * error.c:  Error reporting
+ *
+ * Author:
+ *     Dick Porter (dick@ximian.com)
+ *
+ * (C) 2002 Ximian, Inc.
+ */
+
 #include <config.h>
 #include <glib.h>
 #include <pthread.h>
+#include <string.h>
+#include <errno.h>
 
 #include "mono/io-layer/wapi.h"
 
 static pthread_key_t error_key;
-static pthread_once_t error_key_once=PTHREAD_ONCE_INIT;
+static mono_once_t error_key_once=MONO_ONCE_INIT;
+extern gboolean _wapi_has_shut_down;
 
 static void error_init(void)
 {
-       pthread_key_create(&error_key, NULL);
+       int ret;
+       
+       ret = pthread_key_create(&error_key, NULL);
+       g_assert (ret == 0);
+}
+
+void _wapi_error_cleanup (void)
+{
+       int ret;
+
+       ret = pthread_key_delete (error_key);
+       g_assert (ret == 0);
 }
 
 /**
@@ -24,8 +47,10 @@ guint32 GetLastError(void)
 {
        guint32 err;
        void *errptr;
-       
-       pthread_once(&error_key_once, error_init);
+
+       if (_wapi_has_shut_down)
+               return 0;
+       mono_once(&error_key_once, error_init);
        errptr=pthread_getspecific(error_key);
        err=GPOINTER_TO_UINT(errptr);
        
@@ -40,7 +65,222 @@ guint32 GetLastError(void)
  */
 void SetLastError(guint32 code)
 {
+       int ret;
+       
+       if (_wapi_has_shut_down)
+               return;
        /* Set the thread-local error code */
-       pthread_once(&error_key_once, error_init);
-       pthread_setspecific(error_key, GUINT_TO_POINTER(code));
+       mono_once(&error_key_once, error_init);
+       ret = pthread_setspecific(error_key, GUINT_TO_POINTER(code));
+       g_assert (ret == 0);
+}
+
+guint32
+errno_to_WSA (guint32 code, const gchar *function_name)
+{
+       gint result = -1;
+       char *sys_error;
+       gchar *msg;
+
+       switch (code) {
+       case 0: result = ERROR_SUCCESS; break;
+       case EACCES: result = WSAEACCES; break;
+#ifdef EADDRINUSE
+       case EADDRINUSE: result = WSAEADDRINUSE; break;
+#endif
+#ifdef EAFNOSUPPORT
+       case EAFNOSUPPORT: result = WSAEAFNOSUPPORT; break;
+#endif
+#if EAGAIN != EWOULDBLOCK
+       case EAGAIN: result = WSAEWOULDBLOCK; break;
+#endif
+#ifdef EALREADY
+       case EALREADY: result = WSAEALREADY; break;
+#endif
+       case EBADF: result = WSAENOTSOCK; break;
+#ifdef ECONNABORTED
+       case ECONNABORTED: result = WSAENETDOWN; break;
+#endif
+#ifdef ECONNREFUSED
+       case ECONNREFUSED: result = WSAECONNREFUSED; break;
+#endif
+#ifdef ECONNRESET
+       case ECONNRESET: result = WSAECONNRESET; break;
+#endif
+       case EFAULT: result = WSAEFAULT; break;
+#ifdef EHOSTUNREACH
+       case EHOSTUNREACH: result = WSAEHOSTUNREACH; break;
+#endif
+#ifdef EINPROGRESS
+       case EINPROGRESS: result = WSAEINPROGRESS; break;
+#endif
+       case EINTR: result = WSAEINTR; break;
+       case EINVAL: result = WSAEINVAL; break;
+       /*FIXME: case EIO: result = WSAE????; break; */
+#ifdef EISCONN
+       case EISCONN: result = WSAEISCONN; break;
+#endif
+       /* FIXME: case ELOOP: result = WSA????; break; */
+       case EMFILE: result = WSAEMFILE; break;
+#ifdef EMSGSIZE
+       case EMSGSIZE: result = WSAEMSGSIZE; break;
+#endif
+       /* FIXME: case ENAMETOOLONG: result = WSAEACCES; break; */
+#ifdef ENETUNREACH
+       case ENETUNREACH: result = WSAENETUNREACH; break;
+#endif
+#ifdef ENOBUFS
+       case ENOBUFS: result = WSAENOBUFS; break; /* not documented */
+#endif
+       /* case ENOENT: result = WSAE????; break; */
+       case ENOMEM: result = WSAENOBUFS; break;
+#ifdef ENOPROTOOPT
+       case ENOPROTOOPT: result = WSAENOPROTOOPT; break;
+#endif
+#ifdef ENOSR
+       case ENOSR: result = WSAENETDOWN; break;
+#endif
+#ifdef ENOTCONN
+       case ENOTCONN: result = WSAENOTCONN; break;
+#endif
+       /*FIXME: case ENOTDIR: result = WSAE????; break; */
+#ifdef ENOTSOCK
+       case ENOTSOCK: result = WSAENOTSOCK; break;
+#endif
+       case ENOTTY: result = WSAENOTSOCK; break;
+#ifdef EOPNOTSUPP
+       case EOPNOTSUPP: result = WSAEOPNOTSUPP; break;
+#endif
+       case EPERM: result = WSAEACCES; break;
+       case EPIPE: result = WSAESHUTDOWN; break;
+#ifdef EPROTONOSUPPORT
+       case EPROTONOSUPPORT: result = WSAEPROTONOSUPPORT; break;
+#endif
+#if ERESTARTSYS
+       case ERESTARTSYS: result = WSAENETDOWN; break;
+#endif
+       /*FIXME: case EROFS: result = WSAE????; break; */
+#ifdef ESOCKTNOSUPPORT
+       case ESOCKTNOSUPPORT: result = WSAESOCKTNOSUPPORT; break;
+#endif
+#ifdef ETIMEDOUT
+       case ETIMEDOUT: result = WSAETIMEDOUT; break;
+#endif
+#ifdef EWOULDBLOCK
+       case EWOULDBLOCK: result = WSAEWOULDBLOCK; break;
+#endif
+#ifdef EADDRNOTAVAIL
+       case EADDRNOTAVAIL: result = WSAEADDRNOTAVAIL; break;
+#endif
+       /* This might happen with unix sockets */
+       case ENOENT: result = WSAECONNREFUSED; break;
+#ifdef EDESTADDRREQ
+       case EDESTADDRREQ: result = WSAEDESTADDRREQ; break;
+#endif
+       case ENODEV: result = WSAENETDOWN; break;
+       default:
+               sys_error = strerror (code);
+               msg = g_locale_to_utf8 (sys_error, strlen (sys_error), NULL, NULL, NULL);
+               if (function_name == NULL)
+                       function_name = __func__;
+
+               g_warning ("%s: Need to translate %d [%s] into winsock error",
+                          function_name, code, msg);
+
+               g_free (msg);
+               result = WSASYSCALLFAILURE;
+       }
+
+       return result;
 }
+
+gint
+_wapi_get_win32_file_error (gint err)
+{
+       gint ret;
+       /* mapping ideas borrowed from wine. they may need some work */
+
+       switch (err) {
+       case EACCES: case EPERM: case EROFS:
+               ret = ERROR_ACCESS_DENIED;
+               break;
+       
+       case EAGAIN:
+               ret = ERROR_SHARING_VIOLATION;
+               break;
+       
+       case EBUSY:
+               ret = ERROR_LOCK_VIOLATION;
+               break;
+       
+       case EEXIST:
+               ret = ERROR_FILE_EXISTS;
+               break;
+       
+       case EINVAL: case ESPIPE:
+               ret = ERROR_SEEK;
+               break;
+       
+       case EISDIR:
+               ret = ERROR_CANNOT_MAKE;
+               break;
+       
+       case ENFILE: case EMFILE:
+               ret = ERROR_TOO_MANY_OPEN_FILES;
+               break;
+
+       case ENOENT: case ENOTDIR:
+               ret = ERROR_FILE_NOT_FOUND;
+               break;
+       
+       case ENOSPC:
+               ret = ERROR_HANDLE_DISK_FULL;
+               break;
+       
+       case ENOTEMPTY:
+               ret = ERROR_DIR_NOT_EMPTY;
+               break;
+
+       case ENOEXEC:
+               ret = ERROR_BAD_FORMAT;
+               break;
+
+       case ENAMETOOLONG:
+               ret = ERROR_FILENAME_EXCED_RANGE;
+               break;
+       
+#ifdef EINPROGRESS
+       case EINPROGRESS:
+               ret = ERROR_IO_PENDING;
+               break;
+#endif
+       
+       case ENOSYS:
+               ret = ERROR_NOT_SUPPORTED;
+               break;
+       
+       case EBADF:
+               ret = ERROR_INVALID_HANDLE;
+               break;
+               
+       case EIO:
+               ret = ERROR_INVALID_HANDLE;
+               break;
+               
+       case EINTR:
+               ret = ERROR_IO_PENDING;         /* best match I could find */
+               break;
+               
+       case EPIPE:
+               ret = ERROR_WRITE_FAULT;
+               break;
+               
+       default:
+               g_message ("Unknown errno: %s\n", g_strerror (err));
+               ret = ERROR_GEN_FAILURE;
+               break;
+       }
+
+       return ret;
+}
+