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