Incorporate a few patches from Paolo:
[mono.git] / mono / io-layer / error.c
1 /*
2  * error.c:  Error reporting
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
14 #include <errno.h>
15
16 #include "mono/io-layer/wapi.h"
17
18 static pthread_key_t error_key;
19 static mono_once_t error_key_once=MONO_ONCE_INIT;
20
21 static void error_init(void)
22 {
23         int ret;
24         
25         ret = pthread_key_create(&error_key, NULL);
26         g_assert (ret == 0);
27 }
28
29 void _wapi_error_cleanup (void)
30 {
31         int ret;
32
33         ret = pthread_key_delete (error_key);
34         g_assert (ret == 0);
35 }
36
37 /**
38  * GetLastError:
39  *
40  * Retrieves the last error that occurred in the calling thread.
41  *
42  * Return value: The error code for the last error that happened on
43  * the calling thread.
44  */
45 guint32 GetLastError(void)
46 {
47         guint32 err;
48         void *errptr;
49         
50         mono_once(&error_key_once, error_init);
51         errptr=pthread_getspecific(error_key);
52         err=GPOINTER_TO_UINT(errptr);
53         
54         return(err);
55 }
56
57 /**
58  * SetLastError:
59  * @code: The error code.
60  *
61  * Sets the error code in the calling thread.
62  */
63 void SetLastError(guint32 code)
64 {
65         int ret;
66         
67         /* Set the thread-local error code */
68         mono_once(&error_key_once, error_init);
69         ret = pthread_setspecific(error_key, GUINT_TO_POINTER(code));
70         g_assert (ret == 0);
71 }
72
73 guint32
74 errno_to_WSA (guint32 code, const gchar *function_name)
75 {
76         gint result = -1;
77         char *sys_error;
78         gchar *msg;
79
80         switch (code) {
81         case 0: result = ERROR_SUCCESS; break;
82         case EACCES: result = WSAEACCES; break;
83 #ifdef EADDRINUSE
84         case EADDRINUSE: result = WSAEADDRINUSE; break;
85 #endif
86 #ifdef EAFNOSUPPORT
87         case EAFNOSUPPORT: result = WSAEAFNOSUPPORT; break;
88 #endif
89 #if EAGAIN != EWOULDBLOCK
90         case EAGAIN: result = WSAEWOULDBLOCK; break;
91 #endif
92 #ifdef EALREADY
93         case EALREADY: result = WSAEALREADY; break;
94 #endif
95         case EBADF: result = WSAENOTSOCK; break;
96 #ifdef ECONNABORTED
97         case ECONNABORTED: result = WSAENETDOWN; break;
98 #endif
99 #ifdef ECONNREFUSED
100         case ECONNREFUSED: result = WSAECONNREFUSED; break;
101 #endif
102 #ifdef ECONNRESET
103         case ECONNRESET: result = WSAECONNRESET; break;
104 #endif
105         case EFAULT: result = WSAEFAULT; break;
106 #ifdef EHOSTUNREACH
107         case EHOSTUNREACH: result = WSAEHOSTUNREACH; break;
108 #endif
109 #ifdef EINPROGRESS
110         case EINPROGRESS: result = WSAEINPROGRESS; break;
111 #endif
112         case EINTR: result = WSAEINTR; break;
113         case EINVAL: result = WSAEINVAL; break;
114         /*FIXME: case EIO: result = WSAE????; break; */
115 #ifdef EISCONN
116         case EISCONN: result = WSAEISCONN; break;
117 #endif
118         /* FIXME: case ELOOP: result = WSA????; break; */
119         case EMFILE: result = WSAEMFILE; break;
120 #ifdef EMSGSIZE
121         case EMSGSIZE: result = WSAEMSGSIZE; break;
122 #endif
123         /* FIXME: case ENAMETOOLONG: result = WSAEACCES; break; */
124 #ifdef ENETUNREACH
125         case ENETUNREACH: result = WSAENETUNREACH; break;
126 #endif
127 #ifdef ENOBUFS
128         case ENOBUFS: result = WSAENOBUFS; break; /* not documented */
129 #endif
130         /* case ENOENT: result = WSAE????; break; */
131         case ENOMEM: result = WSAENOBUFS; break;
132 #ifdef ENOPROTOOPT
133         case ENOPROTOOPT: result = WSAENOPROTOOPT; break;
134 #endif
135 #ifdef ENOSR
136         case ENOSR: result = WSAENETDOWN; break;
137 #endif
138 #ifdef ENOTCONN
139         case ENOTCONN: result = WSAENOTCONN; break;
140 #endif
141         /*FIXME: case ENOTDIR: result = WSAE????; break; */
142 #ifdef ENOTSOCK
143         case ENOTSOCK: result = WSAENOTSOCK; break;
144 #endif
145         case ENOTTY: result = WSAENOTSOCK; break;
146 #ifdef EOPNOTSUPP
147         case EOPNOTSUPP: result = WSAEOPNOTSUPP; break;
148 #endif
149         case EPERM: result = WSAEACCES; break;
150         case EPIPE: result = WSAESHUTDOWN; break;
151 #ifdef EPROTONOSUPPORT
152         case EPROTONOSUPPORT: result = WSAEPROTONOSUPPORT; break;
153 #endif
154 #if ERESTARTSYS
155         case ERESTARTSYS: result = WSAENETDOWN; break;
156 #endif
157         /*FIXME: case EROFS: result = WSAE????; break; */
158 #ifdef ESOCKTNOSUPPORT
159         case ESOCKTNOSUPPORT: result = WSAESOCKTNOSUPPORT; break;
160 #endif
161 #ifdef ETIMEDOUT
162         case ETIMEDOUT: result = WSAETIMEDOUT; break;
163 #endif
164 #ifdef EWOULDBLOCK
165         case EWOULDBLOCK: result = WSAEWOULDBLOCK; break;
166 #endif
167 #ifdef EADDRNOTAVAIL
168         case EADDRNOTAVAIL: result = WSAEADDRNOTAVAIL; break;
169 #endif
170         /* This might happen with unix sockets */
171         case ENOENT: result = WSAECONNREFUSED; break;
172 #ifdef EDESTADDRREQ
173         case EDESTADDRREQ: result = WSAEDESTADDRREQ; break;
174 #endif
175         case ENODEV: result = WSAENETDOWN; break;
176         default:
177                 sys_error = strerror (code);
178                 msg = g_locale_to_utf8 (sys_error, strlen (sys_error), NULL, NULL, NULL);
179                 if (function_name == NULL)
180                         function_name = __func__;
181
182                 g_warning ("%s: Need to translate %d [%s] into winsock error",
183                            function_name, code, msg);
184
185                 g_free (msg);
186                 result = WSASYSCALLFAILURE;
187         }
188
189         return result;
190 }
191
192 gint
193 _wapi_get_win32_file_error (gint err)
194 {
195         gint ret;
196         /* mapping ideas borrowed from wine. they may need some work */
197
198         switch (err) {
199         case EACCES: case EPERM: case EROFS:
200                 ret = ERROR_ACCESS_DENIED;
201                 break;
202         
203         case EAGAIN:
204                 ret = ERROR_SHARING_VIOLATION;
205                 break;
206         
207         case EBUSY:
208                 ret = ERROR_LOCK_VIOLATION;
209                 break;
210         
211         case EEXIST:
212                 ret = ERROR_FILE_EXISTS;
213                 break;
214         
215         case EINVAL: case ESPIPE:
216                 ret = ERROR_SEEK;
217                 break;
218         
219         case EISDIR:
220                 ret = ERROR_CANNOT_MAKE;
221                 break;
222         
223         case ENFILE: case EMFILE:
224                 ret = ERROR_TOO_MANY_OPEN_FILES;
225                 break;
226
227         case ENOENT: case ENOTDIR:
228                 ret = ERROR_FILE_NOT_FOUND;
229                 break;
230         
231         case ENOSPC:
232                 ret = ERROR_HANDLE_DISK_FULL;
233                 break;
234         
235         case ENOTEMPTY:
236                 ret = ERROR_DIR_NOT_EMPTY;
237                 break;
238
239         case ENOEXEC:
240                 ret = ERROR_BAD_FORMAT;
241                 break;
242
243         case ENAMETOOLONG:
244                 ret = ERROR_FILENAME_EXCED_RANGE;
245                 break;
246         
247 #ifdef EINPROGRESS
248         case EINPROGRESS:
249                 ret = ERROR_IO_PENDING;
250                 break;
251 #endif
252         
253         case ENOSYS:
254                 ret = ERROR_NOT_SUPPORTED;
255                 break;
256         
257         case EBADF:
258                 ret = ERROR_INVALID_HANDLE;
259                 break;
260                 
261         case EIO:
262                 ret = ERROR_INVALID_HANDLE;
263                 break;
264                 
265         case EINTR:
266                 ret = ERROR_IO_PENDING;         /* best match I could find */
267                 break;
268                 
269         case EPIPE:
270                 ret = ERROR_WRITE_FAULT;
271                 break;
272                 
273         default:
274                 g_message ("Unknown errno: %s\n", g_strerror (err));
275                 ret = ERROR_GEN_FAILURE;
276                 break;
277         }
278
279         return ret;
280 }
281