1*04e0dc4aSTimo Kreuzer //
2*04e0dc4aSTimo Kreuzer // errno.cpp
3*04e0dc4aSTimo Kreuzer //
4*04e0dc4aSTimo Kreuzer // Copyright (c) Microsoft Corporation. All rights reserved.
5*04e0dc4aSTimo Kreuzer //
6*04e0dc4aSTimo Kreuzer // Defines _errno, _doserrno, and related functions
7*04e0dc4aSTimo Kreuzer //
8*04e0dc4aSTimo Kreuzer #define _ALLOW_OLD_VALIDATE_MACROS
9*04e0dc4aSTimo Kreuzer #include <corecrt_internal.h>
10*04e0dc4aSTimo Kreuzer #include <corecrt_internal_ptd_propagation.h>
11*04e0dc4aSTimo Kreuzer #include <errno.h>
12*04e0dc4aSTimo Kreuzer
13*04e0dc4aSTimo Kreuzer
14*04e0dc4aSTimo Kreuzer
15*04e0dc4aSTimo Kreuzer // This is the error table that defines the mapping between OS error codes and
16*04e0dc4aSTimo Kreuzer // errno values.
17*04e0dc4aSTimo Kreuzer namespace
18*04e0dc4aSTimo Kreuzer {
19*04e0dc4aSTimo Kreuzer struct errentry
20*04e0dc4aSTimo Kreuzer {
21*04e0dc4aSTimo Kreuzer unsigned long oscode; // OS return value
22*04e0dc4aSTimo Kreuzer int errnocode; // System V error code
23*04e0dc4aSTimo Kreuzer };
24*04e0dc4aSTimo Kreuzer }
25*04e0dc4aSTimo Kreuzer
26*04e0dc4aSTimo Kreuzer static errentry const errtable[]
27*04e0dc4aSTimo Kreuzer {
28*04e0dc4aSTimo Kreuzer { ERROR_INVALID_FUNCTION, EINVAL }, // 1
29*04e0dc4aSTimo Kreuzer { ERROR_FILE_NOT_FOUND, ENOENT }, // 2
30*04e0dc4aSTimo Kreuzer { ERROR_PATH_NOT_FOUND, ENOENT }, // 3
31*04e0dc4aSTimo Kreuzer { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, // 4
32*04e0dc4aSTimo Kreuzer { ERROR_ACCESS_DENIED, EACCES }, // 5
33*04e0dc4aSTimo Kreuzer { ERROR_INVALID_HANDLE, EBADF }, // 6
34*04e0dc4aSTimo Kreuzer { ERROR_ARENA_TRASHED, ENOMEM }, // 7
35*04e0dc4aSTimo Kreuzer { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, // 8
36*04e0dc4aSTimo Kreuzer { ERROR_INVALID_BLOCK, ENOMEM }, // 9
37*04e0dc4aSTimo Kreuzer { ERROR_BAD_ENVIRONMENT, E2BIG }, // 10
38*04e0dc4aSTimo Kreuzer { ERROR_BAD_FORMAT, ENOEXEC }, // 11
39*04e0dc4aSTimo Kreuzer { ERROR_INVALID_ACCESS, EINVAL }, // 12
40*04e0dc4aSTimo Kreuzer { ERROR_INVALID_DATA, EINVAL }, // 13
41*04e0dc4aSTimo Kreuzer { ERROR_INVALID_DRIVE, ENOENT }, // 15
42*04e0dc4aSTimo Kreuzer { ERROR_CURRENT_DIRECTORY, EACCES }, // 16
43*04e0dc4aSTimo Kreuzer { ERROR_NOT_SAME_DEVICE, EXDEV }, // 17
44*04e0dc4aSTimo Kreuzer { ERROR_NO_MORE_FILES, ENOENT }, // 18
45*04e0dc4aSTimo Kreuzer { ERROR_LOCK_VIOLATION, EACCES }, // 33
46*04e0dc4aSTimo Kreuzer { ERROR_BAD_NETPATH, ENOENT }, // 53
47*04e0dc4aSTimo Kreuzer { ERROR_NETWORK_ACCESS_DENIED, EACCES }, // 65
48*04e0dc4aSTimo Kreuzer { ERROR_BAD_NET_NAME, ENOENT }, // 67
49*04e0dc4aSTimo Kreuzer { ERROR_FILE_EXISTS, EEXIST }, // 80
50*04e0dc4aSTimo Kreuzer { ERROR_CANNOT_MAKE, EACCES }, // 82
51*04e0dc4aSTimo Kreuzer { ERROR_FAIL_I24, EACCES }, // 83
52*04e0dc4aSTimo Kreuzer { ERROR_INVALID_PARAMETER, EINVAL }, // 87
53*04e0dc4aSTimo Kreuzer { ERROR_NO_PROC_SLOTS, EAGAIN }, // 89
54*04e0dc4aSTimo Kreuzer { ERROR_DRIVE_LOCKED, EACCES }, // 108
55*04e0dc4aSTimo Kreuzer { ERROR_BROKEN_PIPE, EPIPE }, // 109
56*04e0dc4aSTimo Kreuzer { ERROR_DISK_FULL, ENOSPC }, // 112
57*04e0dc4aSTimo Kreuzer { ERROR_INVALID_TARGET_HANDLE, EBADF }, // 114
58*04e0dc4aSTimo Kreuzer { ERROR_WAIT_NO_CHILDREN, ECHILD }, // 128
59*04e0dc4aSTimo Kreuzer { ERROR_CHILD_NOT_COMPLETE, ECHILD }, // 129
60*04e0dc4aSTimo Kreuzer { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, // 130
61*04e0dc4aSTimo Kreuzer { ERROR_NEGATIVE_SEEK, EINVAL }, // 131
62*04e0dc4aSTimo Kreuzer { ERROR_SEEK_ON_DEVICE, EACCES }, // 132
63*04e0dc4aSTimo Kreuzer { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, // 145
64*04e0dc4aSTimo Kreuzer { ERROR_NOT_LOCKED, EACCES }, // 158
65*04e0dc4aSTimo Kreuzer { ERROR_BAD_PATHNAME, ENOENT }, // 161
66*04e0dc4aSTimo Kreuzer { ERROR_MAX_THRDS_REACHED, EAGAIN }, // 164
67*04e0dc4aSTimo Kreuzer { ERROR_LOCK_FAILED, EACCES }, // 167
68*04e0dc4aSTimo Kreuzer { ERROR_ALREADY_EXISTS, EEXIST }, // 183
69*04e0dc4aSTimo Kreuzer { ERROR_FILENAME_EXCED_RANGE, ENOENT }, // 206
70*04e0dc4aSTimo Kreuzer { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, // 215
71*04e0dc4aSTimo Kreuzer { ERROR_NO_UNICODE_TRANSLATION, EILSEQ }, // 1113
72*04e0dc4aSTimo Kreuzer { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } // 1816
73*04e0dc4aSTimo Kreuzer };
74*04e0dc4aSTimo Kreuzer
75*04e0dc4aSTimo Kreuzer // Number of elements in the table
76*04e0dc4aSTimo Kreuzer #define ERRTABLECOUNT (sizeof(errtable) / sizeof(errtable[0]))
77*04e0dc4aSTimo Kreuzer
78*04e0dc4aSTimo Kreuzer // The following two constants must be the minimum and maximum
79*04e0dc4aSTimo Kreuzer // values in the (contiguous) range of Exec Failure errors.
80*04e0dc4aSTimo Kreuzer #define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
81*04e0dc4aSTimo Kreuzer #define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
82*04e0dc4aSTimo Kreuzer
83*04e0dc4aSTimo Kreuzer // These are the low and high value in the range of errors that are
84*04e0dc4aSTimo Kreuzer // access violations
85*04e0dc4aSTimo Kreuzer #define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
86*04e0dc4aSTimo Kreuzer #define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
87*04e0dc4aSTimo Kreuzer
88*04e0dc4aSTimo Kreuzer
89*04e0dc4aSTimo Kreuzer
90*04e0dc4aSTimo Kreuzer // These map Windows error codes into errno error codes
__acrt_errno_map_os_error(unsigned long const oserrno)91*04e0dc4aSTimo Kreuzer extern "C" void __cdecl __acrt_errno_map_os_error(unsigned long const oserrno)
92*04e0dc4aSTimo Kreuzer {
93*04e0dc4aSTimo Kreuzer _doserrno = oserrno;
94*04e0dc4aSTimo Kreuzer errno = __acrt_errno_from_os_error(oserrno);
95*04e0dc4aSTimo Kreuzer }
96*04e0dc4aSTimo Kreuzer
__acrt_errno_map_os_error_ptd(unsigned long const oserrno,__crt_cached_ptd_host & ptd)97*04e0dc4aSTimo Kreuzer extern "C" void __cdecl __acrt_errno_map_os_error_ptd(unsigned long const oserrno, __crt_cached_ptd_host& ptd)
98*04e0dc4aSTimo Kreuzer {
99*04e0dc4aSTimo Kreuzer ptd.get_doserrno().set(oserrno);
100*04e0dc4aSTimo Kreuzer ptd.get_errno().set(__acrt_errno_from_os_error(oserrno));
101*04e0dc4aSTimo Kreuzer }
102*04e0dc4aSTimo Kreuzer
__acrt_errno_from_os_error(unsigned long const oserrno)103*04e0dc4aSTimo Kreuzer extern "C" int __cdecl __acrt_errno_from_os_error(unsigned long const oserrno)
104*04e0dc4aSTimo Kreuzer {
105*04e0dc4aSTimo Kreuzer // Check the table for the OS error code
106*04e0dc4aSTimo Kreuzer for (unsigned i{0}; i < ERRTABLECOUNT; ++i)
107*04e0dc4aSTimo Kreuzer {
108*04e0dc4aSTimo Kreuzer if (oserrno == errtable[i].oscode)
109*04e0dc4aSTimo Kreuzer return errtable[i].errnocode;
110*04e0dc4aSTimo Kreuzer }
111*04e0dc4aSTimo Kreuzer
112*04e0dc4aSTimo Kreuzer // The error code wasn't in the table. We check for a range of
113*04e0dc4aSTimo Kreuzer // EACCES errors or exec failure errors (ENOEXEC). Otherwise
114*04e0dc4aSTimo Kreuzer // EINVAL is returned.
115*04e0dc4aSTimo Kreuzer if (oserrno >= MIN_EACCES_RANGE && oserrno <= MAX_EACCES_RANGE)
116*04e0dc4aSTimo Kreuzer {
117*04e0dc4aSTimo Kreuzer return EACCES;
118*04e0dc4aSTimo Kreuzer }
119*04e0dc4aSTimo Kreuzer else if (oserrno >= MIN_EXEC_ERROR && oserrno <= MAX_EXEC_ERROR)
120*04e0dc4aSTimo Kreuzer {
121*04e0dc4aSTimo Kreuzer return ENOEXEC;
122*04e0dc4aSTimo Kreuzer }
123*04e0dc4aSTimo Kreuzer else
124*04e0dc4aSTimo Kreuzer {
125*04e0dc4aSTimo Kreuzer return EINVAL;
126*04e0dc4aSTimo Kreuzer }
127*04e0dc4aSTimo Kreuzer }
128*04e0dc4aSTimo Kreuzer
129*04e0dc4aSTimo Kreuzer
130*04e0dc4aSTimo Kreuzer
131*04e0dc4aSTimo Kreuzer // These safely set and get the value of the calling thread's errno
_set_errno(int const value)132*04e0dc4aSTimo Kreuzer extern "C" errno_t _set_errno(int const value)
133*04e0dc4aSTimo Kreuzer {
134*04e0dc4aSTimo Kreuzer __acrt_ptd* const ptd{__acrt_getptd_noexit()};
135*04e0dc4aSTimo Kreuzer if (!ptd)
136*04e0dc4aSTimo Kreuzer return ENOMEM;
137*04e0dc4aSTimo Kreuzer
138*04e0dc4aSTimo Kreuzer errno = value;
139*04e0dc4aSTimo Kreuzer return 0;
140*04e0dc4aSTimo Kreuzer }
141*04e0dc4aSTimo Kreuzer
_get_errno(int * const result)142*04e0dc4aSTimo Kreuzer extern "C" errno_t _get_errno(int* const result)
143*04e0dc4aSTimo Kreuzer {
144*04e0dc4aSTimo Kreuzer _VALIDATE_RETURN_NOERRNO(result != nullptr, EINVAL);
145*04e0dc4aSTimo Kreuzer
146*04e0dc4aSTimo Kreuzer // Unlike most of our globals, this one is guaranteed to give some answer
147*04e0dc4aSTimo Kreuzer *result = errno;
148*04e0dc4aSTimo Kreuzer return 0;
149*04e0dc4aSTimo Kreuzer }
150*04e0dc4aSTimo Kreuzer
151*04e0dc4aSTimo Kreuzer
152*04e0dc4aSTimo Kreuzer
153*04e0dc4aSTimo Kreuzer // These safely set and get the value of the calling thread's doserrno
_set_doserrno(unsigned long const value)154*04e0dc4aSTimo Kreuzer extern "C" errno_t _set_doserrno(unsigned long const value)
155*04e0dc4aSTimo Kreuzer {
156*04e0dc4aSTimo Kreuzer __acrt_ptd* const ptd{__acrt_getptd_noexit()};
157*04e0dc4aSTimo Kreuzer if (!ptd)
158*04e0dc4aSTimo Kreuzer return ENOMEM;
159*04e0dc4aSTimo Kreuzer
160*04e0dc4aSTimo Kreuzer _doserrno = value;
161*04e0dc4aSTimo Kreuzer return 0;
162*04e0dc4aSTimo Kreuzer }
163*04e0dc4aSTimo Kreuzer
_get_doserrno(unsigned long * const result)164*04e0dc4aSTimo Kreuzer extern "C" errno_t _get_doserrno(unsigned long* const result)
165*04e0dc4aSTimo Kreuzer {
166*04e0dc4aSTimo Kreuzer _VALIDATE_RETURN_NOERRNO(result != nullptr, EINVAL);
167*04e0dc4aSTimo Kreuzer
168*04e0dc4aSTimo Kreuzer // Unlike most of our globals, this one is guaranteed to give some answer:
169*04e0dc4aSTimo Kreuzer *result = _doserrno;
170*04e0dc4aSTimo Kreuzer return 0;
171*04e0dc4aSTimo Kreuzer }
172*04e0dc4aSTimo Kreuzer
173*04e0dc4aSTimo Kreuzer
174*04e0dc4aSTimo Kreuzer
175*04e0dc4aSTimo Kreuzer // These return pointers to the calling thread's errno and doserrno values,
176*04e0dc4aSTimo Kreuzer // respectively, and are used to implement errno and _doserrno in the header.
177*04e0dc4aSTimo Kreuzer static int errno_no_memory {ENOMEM};
178*04e0dc4aSTimo Kreuzer static unsigned long doserrno_no_memory{ERROR_NOT_ENOUGH_MEMORY};
179*04e0dc4aSTimo Kreuzer
_errno()180*04e0dc4aSTimo Kreuzer extern "C" int* __cdecl _errno()
181*04e0dc4aSTimo Kreuzer {
182*04e0dc4aSTimo Kreuzer __acrt_ptd* const ptd{__acrt_getptd_noexit()};
183*04e0dc4aSTimo Kreuzer if (!ptd)
184*04e0dc4aSTimo Kreuzer {
185*04e0dc4aSTimo Kreuzer return &errno_no_memory;
186*04e0dc4aSTimo Kreuzer }
187*04e0dc4aSTimo Kreuzer
188*04e0dc4aSTimo Kreuzer return &ptd->_terrno;
189*04e0dc4aSTimo Kreuzer }
190*04e0dc4aSTimo Kreuzer
__doserrno()191*04e0dc4aSTimo Kreuzer extern "C" unsigned long* __cdecl __doserrno()
192*04e0dc4aSTimo Kreuzer {
193*04e0dc4aSTimo Kreuzer __acrt_ptd* const ptd{__acrt_getptd_noexit()};
194*04e0dc4aSTimo Kreuzer if (!ptd)
195*04e0dc4aSTimo Kreuzer {
196*04e0dc4aSTimo Kreuzer return &doserrno_no_memory;
197*04e0dc4aSTimo Kreuzer }
198*04e0dc4aSTimo Kreuzer
199*04e0dc4aSTimo Kreuzer return &ptd->_tdoserrno;
200*04e0dc4aSTimo Kreuzer }
201