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