Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 20b101d

Browse files
committed
Add errno shim
1 parent 899f247 commit 20b101d

File tree

5 files changed

+419
-0
lines changed

5 files changed

+419
-0
lines changed

src/Native/System.Native/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
project(System.Native)
22

33
set(NATIVE_SOURCES
4+
pal_errno.cpp
45
pal_stat.cpp
56
)
67

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
#define _POSIX_C_SOURCE
5+
6+
#include "../config.h"
7+
#include "pal_errno.h"
8+
9+
#include <errno.h>
10+
#include <string.h>
11+
#include <assert.h>
12+
13+
extern "C"
14+
Error ConvertErrorPlatformToPal(int32_t platformErrno)
15+
{
16+
switch (platformErrno)
17+
{
18+
case 0: return Error::PAL_SUCCESS;
19+
case E2BIG: return Error::PAL_E2BIG;
20+
case EACCES: return Error::PAL_EACCES;
21+
case EADDRINUSE: return Error::PAL_EADDRINUSE;
22+
case EADDRNOTAVAIL: return Error::PAL_EADDRNOTAVAIL;
23+
case EAFNOSUPPORT: return Error::PAL_EAFNOSUPPORT;
24+
case EAGAIN: return Error::PAL_EAGAIN;
25+
case EALREADY: return Error::PAL_EALREADY;
26+
case EBADF: return Error::PAL_EBADF;
27+
case EBADMSG: return Error::PAL_EBADMSG;
28+
case EBUSY: return Error::PAL_EBUSY;
29+
case ECANCELED: return Error::PAL_ECANCELED;
30+
case ECHILD: return Error::PAL_ECHILD;
31+
case ECONNABORTED: return Error::PAL_ECONNABORTED;
32+
case ECONNREFUSED: return Error::PAL_ECONNREFUSED;
33+
case ECONNRESET: return Error::PAL_ECONNRESET;
34+
case EDEADLK: return Error::PAL_EDEADLK;
35+
case EDESTADDRREQ: return Error::PAL_EDESTADDRREQ;
36+
case EDOM: return Error::PAL_EDOM;
37+
case EDQUOT: return Error::PAL_EDQUOT;
38+
case EEXIST: return Error::PAL_EEXIST;
39+
case EFAULT: return Error::PAL_EFAULT;
40+
case EFBIG: return Error::PAL_EFBIG;
41+
case EHOSTUNREACH: return Error::PAL_EHOSTUNREACH;
42+
case EIDRM: return Error::PAL_EIDRM;
43+
case EILSEQ: return Error::PAL_EILSEQ;
44+
case EINPROGRESS: return Error::PAL_EINPROGRESS;
45+
case EINTR: return Error::PAL_EINTR;
46+
case EINVAL: return Error::PAL_EINVAL;
47+
case EIO: return Error::PAL_EIO;
48+
case EISCONN: return Error::PAL_EISCONN;
49+
case EISDIR: return Error::PAL_EISDIR;
50+
case ELOOP: return Error::PAL_ELOOP;
51+
case EMFILE: return Error::PAL_EMFILE;
52+
case EMLINK: return Error::PAL_EMLINK;
53+
case EMSGSIZE: return Error::PAL_EMSGSIZE;
54+
case EMULTIHOP: return Error::PAL_EMULTIHOP;
55+
case ENAMETOOLONG: return Error::PAL_ENAMETOOLONG;
56+
case ENETDOWN: return Error::PAL_ENETDOWN;
57+
case ENETRESET: return Error::PAL_ENETRESET;
58+
case ENETUNREACH: return Error::PAL_ENETUNREACH;
59+
case ENFILE: return Error::PAL_ENFILE;
60+
case ENOBUFS: return Error::PAL_ENOBUFS;
61+
case ENODATA: return Error::PAL_ENODATA;
62+
case ENODEV: return Error::PAL_ENODEV;
63+
case ENOENT: return Error::PAL_ENOENT;
64+
case ENOEXEC: return Error::PAL_ENOEXEC;
65+
case ENOLCK: return Error::PAL_ENOLCK;
66+
case ENOLINK: return Error::PAL_ENOLINK;
67+
case ENOMEM: return Error::PAL_ENOMEM;
68+
case ENOMSG: return Error::PAL_ENOMSG;
69+
case ENOPROTOOPT: return Error::PAL_ENOPROTOOPT;
70+
case ENOSPC: return Error::PAL_ENOSPC;
71+
case ENOSR: return Error::PAL_ENOSR;
72+
case ENOSTR: return Error::PAL_ENOSTR;
73+
case ENOSYS: return Error::PAL_ENOSYS;
74+
case ENOTCONN: return Error::PAL_ENOTCONN;
75+
case ENOTDIR: return Error::PAL_ENOTDIR;
76+
case ENOTEMPTY: return Error::PAL_ENOTEMPTY;
77+
case ENOTRECOVERABLE: return Error::PAL_ENOTRECOVERABLE;
78+
case ENOTSOCK: return Error::PAL_ENOTSOCK;
79+
case ENOTSUP: return Error::PAL_ENOTSUP;
80+
case ENOTTY: return Error::PAL_ENOTTY;
81+
case ENXIO: return Error::PAL_ENXIO;
82+
case EOVERFLOW: return Error::PAL_EOVERFLOW;
83+
case EOWNERDEAD: return Error::PAL_EOWNERDEAD;
84+
case EPERM: return Error::PAL_EPERM;
85+
case EPIPE: return Error::PAL_EPIPE;
86+
case EPROTO: return Error::PAL_EPROTO;
87+
case EPROTONOSUPPORT: return Error::PAL_EPROTONOSUPPORT;
88+
case EPROTOTYPE: return Error::PAL_EPROTOTYPE;
89+
case ERANGE: return Error::PAL_ERANGE;
90+
case EROFS: return Error::PAL_EROFS;
91+
case ESPIPE: return Error::PAL_ESPIPE;
92+
case ESRCH: return Error::PAL_ESRCH;
93+
case ESTALE: return Error::PAL_ESTALE;
94+
case ETIME: return Error::PAL_ETIME;
95+
case ETIMEDOUT: return Error::PAL_ETIMEDOUT;
96+
case ETXTBSY: return Error::PAL_ETXTBSY;
97+
case EXDEV: return Error::PAL_EXDEV;
98+
99+
// #if because these will trigger duplicate case label warnings when
100+
// they have the same value, which is permitted by POSIX and common.
101+
#if EOPNOTSUPP != ENOTSUP
102+
case EOPNOTSUPP: return Error::PAL_EOPNOTSUPP;
103+
#endif
104+
#if EWOULDBLOCK != EAGAIN
105+
case EWOULDBLOCK: return Error::PAL_EWOULDBLOCK;
106+
#endif
107+
}
108+
109+
return Error::PAL_ENONSTANDARD;
110+
}
111+
112+
extern "C"
113+
int32_t ConvertErrorPalToPlatform(Error error)
114+
{
115+
switch (error)
116+
{
117+
case Error::PAL_SUCCESS: return 0;
118+
case Error::PAL_E2BIG: return E2BIG;
119+
case Error::PAL_EACCES: return EACCES;
120+
case Error::PAL_EADDRINUSE: return EADDRINUSE;
121+
case Error::PAL_EADDRNOTAVAIL: return EADDRNOTAVAIL;
122+
case Error::PAL_EAFNOSUPPORT: return EAFNOSUPPORT;
123+
case Error::PAL_EAGAIN: return EAGAIN;
124+
case Error::PAL_EALREADY: return EALREADY;
125+
case Error::PAL_EBADF: return EBADF;
126+
case Error::PAL_EBADMSG: return EBADMSG;
127+
case Error::PAL_EBUSY: return EBUSY;
128+
case Error::PAL_ECANCELED: return ECANCELED;
129+
case Error::PAL_ECHILD: return ECHILD;
130+
case Error::PAL_ECONNABORTED: return ECONNABORTED;
131+
case Error::PAL_ECONNREFUSED: return ECONNREFUSED;
132+
case Error::PAL_ECONNRESET: return ECONNRESET;
133+
case Error::PAL_EDEADLK: return EDEADLK;
134+
case Error::PAL_EDESTADDRREQ: return EDESTADDRREQ;
135+
case Error::PAL_EDOM: return EDOM;
136+
case Error::PAL_EDQUOT: return EDQUOT;
137+
case Error::PAL_EEXIST: return EEXIST;
138+
case Error::PAL_EFAULT: return EFAULT;
139+
case Error::PAL_EFBIG: return EFBIG;
140+
case Error::PAL_EHOSTUNREACH: return EHOSTUNREACH;
141+
case Error::PAL_EIDRM: return EIDRM;
142+
case Error::PAL_EILSEQ: return EILSEQ;
143+
case Error::PAL_EINPROGRESS: return EINPROGRESS;
144+
case Error::PAL_EINTR: return EINTR;
145+
case Error::PAL_EINVAL: return EINVAL;
146+
case Error::PAL_EIO: return EIO;
147+
case Error::PAL_EISCONN: return EISCONN;
148+
case Error::PAL_EISDIR: return EISDIR;
149+
case Error::PAL_ELOOP: return ELOOP;
150+
case Error::PAL_EMFILE: return EMFILE;
151+
case Error::PAL_EMLINK: return EMLINK;
152+
case Error::PAL_EMSGSIZE: return EMSGSIZE;
153+
case Error::PAL_EMULTIHOP: return EMULTIHOP;
154+
case Error::PAL_ENAMETOOLONG: return ENAMETOOLONG;
155+
case Error::PAL_ENETDOWN: return ENETDOWN;
156+
case Error::PAL_ENETRESET: return ENETRESET;
157+
case Error::PAL_ENETUNREACH: return ENETUNREACH;
158+
case Error::PAL_ENFILE: return ENFILE;
159+
case Error::PAL_ENOBUFS: return ENOBUFS;
160+
case Error::PAL_ENODATA: return ENODATA;
161+
case Error::PAL_ENODEV: return ENODEV;
162+
case Error::PAL_ENOENT: return ENOENT;
163+
case Error::PAL_ENOEXEC: return ENOEXEC;
164+
case Error::PAL_ENOLCK: return ENOLCK;
165+
case Error::PAL_ENOLINK: return ENOLINK;
166+
case Error::PAL_ENOMEM: return ENOMEM;
167+
case Error::PAL_ENOMSG: return ENOMSG;
168+
case Error::PAL_ENOPROTOOPT: return ENOPROTOOPT;
169+
case Error::PAL_ENOSPC: return ENOSPC;
170+
case Error::PAL_ENOSR: return ENOSR;
171+
case Error::PAL_ENOSTR: return ENOSTR;
172+
case Error::PAL_ENOSYS: return ENOSYS;
173+
case Error::PAL_ENOTCONN: return ENOTCONN;
174+
case Error::PAL_ENOTDIR: return ENOTDIR;
175+
case Error::PAL_ENOTEMPTY: return ENOTEMPTY;
176+
case Error::PAL_ENOTRECOVERABLE: return ENOTRECOVERABLE;
177+
case Error::PAL_ENOTSOCK: return ENOTSOCK;
178+
case Error::PAL_ENOTSUP: return ENOTSUP;
179+
case Error::PAL_ENOTTY: return ENOTTY;
180+
case Error::PAL_ENXIO: return ENXIO;
181+
case Error::PAL_EOVERFLOW: return EOVERFLOW;
182+
case Error::PAL_EOWNERDEAD: return EOWNERDEAD;
183+
case Error::PAL_EPERM: return EPERM;
184+
case Error::PAL_EPIPE: return EPIPE;
185+
case Error::PAL_EPROTO: return EPROTO;
186+
case Error::PAL_EPROTONOSUPPORT: return EPROTONOSUPPORT;
187+
case Error::PAL_EPROTOTYPE: return EPROTOTYPE;
188+
case Error::PAL_ERANGE: return ERANGE;
189+
case Error::PAL_EROFS: return EROFS;
190+
case Error::PAL_ESPIPE: return ESPIPE;
191+
case Error::PAL_ESRCH: return ESRCH;
192+
case Error::PAL_ESTALE: return ESTALE;
193+
case Error::PAL_ETIME: return ETIME;
194+
case Error::PAL_ETIMEDOUT: return ETIMEDOUT;
195+
case Error::PAL_ETXTBSY: return ETXTBSY;
196+
case Error::PAL_EXDEV: return EXDEV;
197+
case Error::PAL_ENONSTANDARD: break; // fall through to assert
198+
}
199+
200+
// We should not use this function to round-trip platform -> pal
201+
// -> platform. It's here only to synthesize a platform number
202+
// from the fixed set above. Note that the assert is outside the
203+
// switch rather than in a default case default block because not
204+
// having a default will trigger a warning (as error) if there's
205+
// an enum value we haven't handled. Should that trigger, make
206+
// note that there is probably a corresponding missing case in the
207+
// other direction above, but the compiler can't warn in that case
208+
// because the platform values are not part of an enum.
209+
assert(false);
210+
return -1;
211+
}
212+
213+
extern "C"
214+
const char* StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize)
215+
{
216+
assert(buffer != nullptr);
217+
assert(bufferSize > 0);
218+
219+
// Note that we must use strerror_r because plain strerror is not
220+
// thread-safe.
221+
//
222+
// However, there are two versions of strerror_r:
223+
// - GNU: char* strerror_r(int, char*, size_t);
224+
// - POSIX: int strerror_r(int, char*, size_t);
225+
//
226+
// The former may or may not use the supplied buffer, and returns
227+
// the error message string. The latter stores the error message
228+
// string into the supplied buffer.
229+
230+
#if HAVE_GNU_STRERROR_R
231+
return strerror_r(platformErrno, buffer, bufferSize);
232+
#else
233+
// We deliberately ignore the return value here. The only three
234+
// valid return values are 0 for success, EINVAL for an unknown
235+
// errno value, and ERANGE if there's not enough buffer space
236+
// provided. For EINVAL, it'll still fill the buffer with a
237+
// reasonable error string (e.g. "Unknown error: 0x123"), and for
238+
// ERANGE, it'll fill the buffer with as much of the error as it
239+
// can and null-terminate it.
240+
//
241+
// Note that although we ignore the error code, we still assign it
242+
// to a local to force a compilation error if we somehow end up
243+
// with GNU strerror_r yet HAVE_GNU_STRERROR_R == 0 due to a
244+
// configuration error.
245+
int ignored = strerror_r(platformErrno, buffer, bufferSize);
246+
(void)ignored; // suppress compiler warning about unused local
247+
return buffer;
248+
#endif
249+
}

0 commit comments

Comments
 (0)