1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999,2008 Oracle.  All rights reserved.
5 *
6 * $Id: os_errno.c,v 12.15 2008/01/08 20:58:46 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12
13/*
14 * __os_get_errno_ret_zero --
15 *	Return the last system error, including an error of zero.
16 */
17int
18__os_get_errno_ret_zero()
19{
20	/* This routine must be able to return the same value repeatedly. */
21	return (errno);
22}
23
24/*
25 * We've seen cases where system calls failed but errno was never set.  For
26 * that reason, __os_get_errno() and __os_get_syserr set errno to EAGAIN if
27 * it's not already set, to work around the problem.  For obvious reasons,
28 * we can only call this function if we know an error has occurred, that
29 * is, we can't test the return for a non-zero value after the get call.
30 *
31 * __os_get_errno --
32 *	Return the last ANSI C "errno" value or EAGAIN if the last error
33 *	is zero.
34 */
35int
36__os_get_errno()
37{
38	/* This routine must be able to return the same value repeatedly. */
39	if (errno == 0)
40		__os_set_errno(EAGAIN);
41	return (errno);
42}
43
44#ifdef HAVE_REPLICATION_THREADS
45/*
46 * __os_get_neterr --
47 *	Return the last networking error or EAGAIN if the last error is zero.
48 *
49 * PUBLIC: #ifdef HAVE_REPLICATION_THREADS
50 * PUBLIC: int __os_get_neterr __P((void));
51 * PUBLIC: #endif
52 */
53int
54__os_get_neterr()
55{
56	int err;
57
58	/* This routine must be able to return the same value repeatedly. */
59	err = WSAGetLastError();
60	if (err == 0)
61		WSASetLastError(err = ERROR_RETRY);
62	return (err);
63}
64#endif
65
66/*
67 * __os_get_syserr --
68 *	Return the last system error or EAGAIN if the last error is zero.
69 */
70int
71__os_get_syserr()
72{
73	int err;
74
75	/* This routine must be able to return the same value repeatedly. */
76	err = GetLastError();
77	if (err == 0)
78		SetLastError(err = ERROR_RETRY);
79	return (err);
80}
81
82/*
83 * __os_set_errno --
84 *	Set the value of errno.
85 */
86void
87__os_set_errno(evalue)
88	int evalue;
89{
90	/*
91	 * This routine is called by the compatibility interfaces (DB 1.85,
92	 * dbm and hsearch).  Force values > 0, that is, not one of DB 2.X
93	 * and later's public error returns.  If something bad has happened,
94	 * default to EFAULT -- a nasty return.  Otherwise, default to EINVAL.
95	 * As the compatibility APIs aren't included on Windows, the Windows
96	 * version of this routine doesn't need this behavior.
97	 */
98	errno =
99	    evalue >= 0 ? evalue : (evalue == DB_RUNRECOVERY ? EFAULT : EINVAL);
100}
101
102/*
103 * __os_strerror --
104 *	Return a string associated with the system error.
105 */
106char *
107__os_strerror(error, buf, len)
108	int error;
109	char *buf;
110	size_t len;
111{
112#ifdef DB_WINCE
113#define	MAX_TMPBUF_LEN 512
114	_TCHAR tbuf[MAX_TMPBUF_LEN];
115	size_t  maxlen;
116
117	DB_ASSERT(NULL, error != 0);
118
119	memset(tbuf, 0, sizeof(_TCHAR)*MAX_TMPBUF_LEN);
120	maxlen = (len > MAX_TMPBUF_LEN ? MAX_TMPBUF_LEN : len);
121	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, (DWORD)error,
122		0, tbuf, maxlen-1, NULL);
123
124	if (WideCharToMultiByte(CP_UTF8, 0, tbuf, -1,
125		buf, len, 0, NULL) == 0)
126		strncpy(buf, "Error message translation failed.", len);
127#else
128	DB_ASSERT(NULL, error != 0);
129	/*
130	 * Explicitly call FormatMessageA, since we want to receive a char
131	 * string back, not a tchar string.
132	 */
133	FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
134	    0, (DWORD)error, 0, buf, (DWORD)(len - 1), NULL);
135	buf[len - 1] = '\0';
136#endif
137
138	return (buf);
139}
140
141/*
142 * __os_posix_err --
143 *	Convert a system error to a POSIX error.
144 */
145int
146__os_posix_err(error)
147	int error;
148{
149	/* Handle calls on successful returns. */
150	if (error == 0)
151		return (0);
152
153	/*
154	 * Translate the Windows error codes we care about.
155	 */
156	switch (error) {
157	case ERROR_INVALID_PARAMETER:
158		return (EINVAL);
159
160	case ERROR_FILE_NOT_FOUND:
161	case ERROR_INVALID_DRIVE:
162	case ERROR_PATH_NOT_FOUND:
163		return (ENOENT);
164
165	case ERROR_NO_MORE_FILES:
166	case ERROR_TOO_MANY_OPEN_FILES:
167		return (EMFILE);
168
169	case ERROR_ACCESS_DENIED:
170		return (EPERM);
171
172	case ERROR_INVALID_HANDLE:
173		return (EBADF);
174
175	case ERROR_NOT_ENOUGH_MEMORY:
176		return (ENOMEM);
177
178	case ERROR_DISK_FULL:
179		return (ENOSPC);
180
181	case ERROR_ARENA_TRASHED:
182	case ERROR_BAD_COMMAND:
183	case ERROR_BAD_ENVIRONMENT:
184	case ERROR_BAD_FORMAT:
185	case ERROR_GEN_FAILURE:
186	case ERROR_INVALID_ACCESS:
187	case ERROR_INVALID_BLOCK:
188	case ERROR_INVALID_DATA:
189	case ERROR_READ_FAULT:
190	case ERROR_WRITE_FAULT:
191		return (EFAULT);
192
193	case ERROR_ALREADY_EXISTS:
194	case ERROR_FILE_EXISTS:
195		return (EEXIST);
196
197	case ERROR_NOT_SAME_DEVICE:
198		return (EXDEV);
199
200	case ERROR_WRITE_PROTECT:
201		return (EACCES);
202
203	case ERROR_LOCK_FAILED:
204	case ERROR_LOCK_VIOLATION:
205	case ERROR_NOT_READY:
206	case ERROR_SHARING_VIOLATION:
207		return (EBUSY);
208
209	case ERROR_RETRY:
210		return (EINTR);
211	}
212
213	/*
214	 * Translate the Windows socket error codes.
215	 */
216	switch (error) {
217	case WSAEADDRINUSE:
218#ifdef EADDRINUSE
219		return (EADDRINUSE);
220#else
221		break;
222#endif
223	case WSAEADDRNOTAVAIL:
224#ifdef EADDRNOTAVAIL
225		return (EADDRNOTAVAIL);
226#else
227		break;
228#endif
229	case WSAEAFNOSUPPORT:
230#ifdef EAFNOSUPPORT
231		return (EAFNOSUPPORT);
232#else
233		break;
234#endif
235	case WSAEALREADY:
236#ifdef EALREADY
237		return (EALREADY);
238#else
239		break;
240#endif
241	case WSAEBADF:
242		return (EBADF);
243	case WSAECONNABORTED:
244#ifdef ECONNABORTED
245		return (ECONNABORTED);
246#else
247		break;
248#endif
249	case WSAECONNREFUSED:
250#ifdef ECONNREFUSED
251		return (ECONNREFUSED);
252#else
253		break;
254#endif
255	case WSAECONNRESET:
256#ifdef ECONNRESET
257		return (ECONNRESET);
258#else
259		break;
260#endif
261	case WSAEDESTADDRREQ:
262#ifdef EDESTADDRREQ
263		return (EDESTADDRREQ);
264#else
265		break;
266#endif
267	case WSAEFAULT:
268		return (EFAULT);
269	case WSAEHOSTDOWN:
270#ifdef EHOSTDOWN
271		return (EHOSTDOWN);
272#else
273		break;
274#endif
275	case WSAEHOSTUNREACH:
276#ifdef EHOSTUNREACH
277		return (EHOSTUNREACH);
278#else
279		break;
280#endif
281	case WSAEINPROGRESS:
282#ifdef EINPROGRESS
283		return (EINPROGRESS);
284#else
285		break;
286#endif
287	case WSAEINTR:
288		return (EINTR);
289	case WSAEINVAL:
290		return (EINVAL);
291	case WSAEISCONN:
292#ifdef EISCONN
293		return (EISCONN);
294#else
295		break;
296#endif
297	case WSAELOOP:
298#ifdef ELOOP
299		return (ELOOP);
300#else
301		break;
302#endif
303	case WSAEMFILE:
304		return (EMFILE);
305	case WSAEMSGSIZE:
306#ifdef EMSGSIZE
307		return (EMSGSIZE);
308#else
309		break;
310#endif
311	case WSAENAMETOOLONG:
312		return (ENAMETOOLONG);
313	case WSAENETDOWN:
314#ifdef ENETDOWN
315		return (ENETDOWN);
316#else
317		break;
318#endif
319	case WSAENETRESET:
320#ifdef ENETRESET
321		return (ENETRESET);
322#else
323		break;
324#endif
325	case WSAENETUNREACH:
326#ifdef ENETUNREACH
327		return (ENETUNREACH);
328#else
329		break;
330#endif
331	case WSAENOBUFS:
332#ifdef ENOBUFS
333		return (ENOBUFS);
334#else
335		break;
336#endif
337	case WSAENOPROTOOPT:
338#ifdef ENOPROTOOPT
339		return (ENOPROTOOPT);
340#else
341		break;
342#endif
343	case WSAENOTCONN:
344#ifdef ENOTCONN
345		return (ENOTCONN);
346#else
347		break;
348#endif
349	case WSANOTINITIALISED:
350		return (EAGAIN);
351	case WSAENOTSOCK:
352#ifdef ENOTSOCK
353		return (ENOTSOCK);
354#else
355		break;
356#endif
357	case WSAEOPNOTSUPP:
358		return (DB_OPNOTSUP);
359	case WSAEPFNOSUPPORT:
360#ifdef EPFNOSUPPORT
361		return (EPFNOSUPPORT);
362#else
363		break;
364#endif
365	case WSAEPROTONOSUPPORT:
366#ifdef EPROTONOSUPPORT
367		return (EPROTONOSUPPORT);
368#else
369		break;
370#endif
371	case WSAEPROTOTYPE:
372#ifdef EPROTOTYPE
373		return (EPROTOTYPE);
374#else
375		break;
376#endif
377	case WSAESHUTDOWN:
378#ifdef ESHUTDOWN
379		return (ESHUTDOWN);
380#else
381		break;
382#endif
383	case WSAESOCKTNOSUPPORT:
384#ifdef ESOCKTNOSUPPORT
385		return (ESOCKTNOSUPPORT);
386#else
387		break;
388#endif
389	case WSAETIMEDOUT:
390#ifdef ETIMEDOUT
391		return (ETIMEDOUT);
392#else
393		break;
394#endif
395	case WSAETOOMANYREFS:
396#ifdef ETOOMANYREFS
397		return (ETOOMANYREFS);
398#else
399		break;
400#endif
401	case WSAEWOULDBLOCK:
402#ifdef EWOULDBLOCK
403		return (EWOULDBLOCK);
404#else
405		return (EAGAIN);
406#endif
407	case WSAHOST_NOT_FOUND:
408#ifdef EHOSTUNREACH
409		return (EHOSTUNREACH);
410#else
411		break;
412#endif
413	case WSASYSNOTREADY:
414		return (EAGAIN);
415	case WSATRY_AGAIN:
416		return (EAGAIN);
417	case WSAVERNOTSUPPORTED:
418		return (DB_OPNOTSUP);
419	case WSAEACCES:
420		return (EACCES);
421	}
422
423	/*
424	 * EFAULT is the default if we don't have a translation.
425	 */
426	return (EFAULT);
427}
428