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