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