xref: /reactos/sdk/lib/ucrt/misc/errno.cpp (revision fe93a3f9)
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
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 
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 
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
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 
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
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 
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 
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 
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