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