Reactos
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.
17namespace
18{
19 struct errentry
20 {
21 unsigned long oscode; // OS return value
22 int errnocode; // System V error code
23 };
24}
25
26static 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
91extern "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
97extern "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
103extern "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
132extern "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
142extern "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
154extern "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
164extern "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.
177static int errno_no_memory {ENOMEM};
178static unsigned long doserrno_no_memory{ERROR_NOT_ENOUGH_MEMORY};
179
180extern "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
191extern "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}