| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | /*++ |
| 6 | |
| 7 | |
| 8 | |
| 9 | Module Name: |
| 10 | |
| 11 | misc/utils.c |
| 12 | |
| 13 | Abstract: |
| 14 | |
| 15 | Miscellaneous helper functions for the PAL, which don't fit anywhere else |
| 16 | |
| 17 | |
| 18 | |
| 19 | --*/ |
| 20 | |
| 21 | #include "pal/dbgmsg.h" |
| 22 | SET_DEFAULT_DEBUG_CHANNEL(MISC); // some headers have code with asserts, so do this first |
| 23 | |
| 24 | #include "pal/palinternal.h" |
| 25 | #if HAVE_VM_ALLOCATE |
| 26 | #include <mach/message.h> |
| 27 | #endif //HAVE_VM_ALLOCATE |
| 28 | |
| 29 | #include "pal/utils.h" |
| 30 | #include "pal/file.h" |
| 31 | |
| 32 | #include <errno.h> |
| 33 | #include <string.h> |
| 34 | |
| 35 | |
| 36 | // In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable |
| 37 | // defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement |
| 38 | // should be placed after the SET_DEFAULT_DEBUG_CHANNEL(MISC) |
| 39 | #include <safemath.h> |
| 40 | |
| 41 | /*++ |
| 42 | Function: |
| 43 | UTIL_inverse_wcspbrk |
| 44 | |
| 45 | Opposite of wcspbrk : searches a string for the first character NOT in the |
| 46 | given set |
| 47 | |
| 48 | Parameters : |
| 49 | LPWSTR lpwstr : string to search |
| 50 | LPCWSTR charset : list of characters to search for |
| 51 | |
| 52 | Return value : |
| 53 | pointer to first character of lpwstr that isn't in the set |
| 54 | NULL if all characters are in the set |
| 55 | --*/ |
| 56 | LPWSTR UTIL_inverse_wcspbrk(LPWSTR lpwstr, LPCWSTR charset) |
| 57 | { |
| 58 | while(*lpwstr) |
| 59 | { |
| 60 | if(NULL == PAL_wcschr(charset,*lpwstr)) |
| 61 | { |
| 62 | return lpwstr; |
| 63 | } |
| 64 | lpwstr++; |
| 65 | } |
| 66 | return NULL; |
| 67 | } |
| 68 | |
| 69 | |
| 70 | /*++ |
| 71 | Function : |
| 72 | UTIL_IsReadOnlyBitsSet |
| 73 | |
| 74 | Takes a struct stat * |
| 75 | Returns true if the file is read only, |
| 76 | --*/ |
| 77 | BOOL UTIL_IsReadOnlyBitsSet( struct stat * stat_data ) |
| 78 | { |
| 79 | BOOL bRetVal = FALSE; |
| 80 | |
| 81 | /* Check for read permissions. */ |
| 82 | if ( stat_data->st_uid == geteuid() ) |
| 83 | { |
| 84 | /* The process owner is the file owner as well. */ |
| 85 | if ( ( stat_data->st_mode & S_IRUSR ) && !( stat_data->st_mode & S_IWUSR ) ) |
| 86 | { |
| 87 | bRetVal = TRUE; |
| 88 | } |
| 89 | } |
| 90 | else if ( stat_data->st_gid == getegid() ) |
| 91 | { |
| 92 | /* The process's owner is in the same group as the file's owner. */ |
| 93 | if ( ( stat_data->st_mode & S_IRGRP ) && !( stat_data->st_mode & S_IWGRP ) ) |
| 94 | { |
| 95 | bRetVal = TRUE; |
| 96 | } |
| 97 | } |
| 98 | else |
| 99 | { |
| 100 | /* Check the other bits to see who can access the file. */ |
| 101 | if ( ( stat_data->st_mode & S_IROTH ) && !( stat_data->st_mode & S_IWOTH ) ) |
| 102 | { |
| 103 | bRetVal = TRUE; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | return bRetVal; |
| 108 | } |
| 109 | |
| 110 | /*++ |
| 111 | Function : |
| 112 | UTIL_IsExecuteBitsSet |
| 113 | |
| 114 | Takes a struct stat * |
| 115 | Returns true if the file is executable, |
| 116 | --*/ |
| 117 | BOOL UTIL_IsExecuteBitsSet( struct stat * stat_data ) |
| 118 | { |
| 119 | BOOL bRetVal = FALSE; |
| 120 | |
| 121 | if ( (stat_data->st_mode & S_IFMT) == S_IFDIR ) |
| 122 | { |
| 123 | return FALSE; |
| 124 | } |
| 125 | |
| 126 | /* Check for read permissions. */ |
| 127 | if ( 0 == geteuid() ) |
| 128 | { |
| 129 | /* The process owner is root */ |
| 130 | bRetVal = TRUE; |
| 131 | } |
| 132 | else if ( stat_data->st_uid == geteuid() ) |
| 133 | { |
| 134 | /* The process owner is the file owner as well. */ |
| 135 | if ( ( stat_data->st_mode & S_IXUSR ) ) |
| 136 | { |
| 137 | bRetVal = TRUE; |
| 138 | } |
| 139 | } |
| 140 | else if ( stat_data->st_gid == getegid() ) |
| 141 | { |
| 142 | /* The process's owner is in the same group as the file's owner. */ |
| 143 | if ( ( stat_data->st_mode & S_IXGRP ) ) |
| 144 | { |
| 145 | bRetVal = TRUE; |
| 146 | } |
| 147 | } |
| 148 | else |
| 149 | { |
| 150 | /* Check the other bits to see who can access the file. */ |
| 151 | if ( ( stat_data->st_mode & S_IXOTH ) ) |
| 152 | { |
| 153 | bRetVal = TRUE; |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | return bRetVal; |
| 158 | } |
| 159 | |
| 160 | /*++ |
| 161 | Function : |
| 162 | UTIL_WCToMB_Alloc |
| 163 | |
| 164 | Converts a wide string to a multibyte string, allocating the required buffer |
| 165 | |
| 166 | Parameters : |
| 167 | LPCWSTR lpWideCharStr : string to convert |
| 168 | int cchWideChar : number of wide characters to convert |
| 169 | (-1 to convert a complete null-termnated string) |
| 170 | |
| 171 | Return Value : |
| 172 | newly allocated buffer containing the converted string. Conversion is |
| 173 | performed using CP_ACP. Buffer is allocated with malloc(), release it |
| 174 | with free(). |
| 175 | In case if failure, LastError will be set. |
| 176 | --*/ |
| 177 | LPSTR UTIL_WCToMB_Alloc(LPCWSTR lpWideCharStr, int cchWideChar) |
| 178 | { |
| 179 | int length; |
| 180 | LPSTR lpMultiByteStr; |
| 181 | |
| 182 | /* get required buffer length */ |
| 183 | length = WideCharToMultiByte(CP_ACP, 0, lpWideCharStr, cchWideChar, |
| 184 | NULL, 0, NULL, NULL); |
| 185 | if(0 == length) |
| 186 | { |
| 187 | ERROR("WCToMB error; GetLastError returns %#x" , GetLastError()); |
| 188 | return NULL; |
| 189 | } |
| 190 | |
| 191 | /* allocate required buffer */ |
| 192 | lpMultiByteStr = (LPSTR)PAL_malloc(length); |
| 193 | if(NULL == lpMultiByteStr) |
| 194 | { |
| 195 | ERROR("malloc() failed! errno is %d (%s)\n" , errno,strerror(errno)); |
| 196 | SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| 197 | return NULL; |
| 198 | } |
| 199 | |
| 200 | /* convert into allocated buffer */ |
| 201 | length = WideCharToMultiByte(CP_ACP, 0, lpWideCharStr, cchWideChar, |
| 202 | lpMultiByteStr, length, NULL, NULL); |
| 203 | if(0 == length) |
| 204 | { |
| 205 | ASSERT("WCToMB error; GetLastError returns %#x\n" , GetLastError()); |
| 206 | PAL_free(lpMultiByteStr); |
| 207 | return NULL; |
| 208 | } |
| 209 | return lpMultiByteStr; |
| 210 | } |
| 211 | |
| 212 | /*++ |
| 213 | Function : |
| 214 | UTIL_MBToWC_Alloc |
| 215 | |
| 216 | Converts a multibyte string to a wide string, allocating the required buffer |
| 217 | |
| 218 | Parameters : |
| 219 | LPCSTR lpMultiByteStr : string to convert |
| 220 | int cbMultiByte : number of bytes to convert |
| 221 | (-1 to convert a complete null-termnated string) |
| 222 | |
| 223 | Return Value : |
| 224 | newly allocated buffer containing the converted string. Conversion is |
| 225 | performed using CP_ACP. Buffer is allocated with malloc(), release it |
| 226 | with free(). |
| 227 | In case if failure, LastError will be set. |
| 228 | --*/ |
| 229 | LPWSTR UTIL_MBToWC_Alloc(LPCSTR lpMultiByteStr, int cbMultiByte) |
| 230 | { |
| 231 | int length; |
| 232 | LPWSTR lpWideCharStr; |
| 233 | |
| 234 | /* get required buffer length */ |
| 235 | length = MultiByteToWideChar(CP_ACP, 0, lpMultiByteStr, cbMultiByte, |
| 236 | NULL, 0); |
| 237 | if(0 == length) |
| 238 | { |
| 239 | ERROR("MBToWC error; GetLastError returns %#x" , GetLastError()); |
| 240 | return NULL; |
| 241 | } |
| 242 | |
| 243 | /* allocate required buffer */ |
| 244 | size_t fullsize; |
| 245 | if (!ClrSafeInt<size_t>::multiply(length,sizeof(WCHAR),fullsize)) |
| 246 | { |
| 247 | ERROR("integer overflow! length = %d , sizeof(WCHAR) = (%d)\n" , length,sizeof(WCHAR) ); |
| 248 | SetLastError(ERROR_ARITHMETIC_OVERFLOW); |
| 249 | return NULL; |
| 250 | } |
| 251 | |
| 252 | lpWideCharStr = (LPWSTR)PAL_malloc(fullsize); |
| 253 | if(NULL == lpWideCharStr) |
| 254 | { |
| 255 | ERROR("malloc() failed! errno is %d (%s)\n" , errno,strerror(errno)); |
| 256 | SetLastError(FILEGetLastErrorFromErrno()); |
| 257 | return NULL; |
| 258 | } |
| 259 | |
| 260 | /* convert into allocated buffer */ |
| 261 | length = MultiByteToWideChar(CP_ACP, 0, lpMultiByteStr, cbMultiByte, |
| 262 | lpWideCharStr, length); |
| 263 | if(0 >= length) |
| 264 | { |
| 265 | ASSERT("MCToMB error; GetLastError returns %#x\n" , GetLastError()); |
| 266 | PAL_free(lpWideCharStr); |
| 267 | return NULL; |
| 268 | } |
| 269 | return lpWideCharStr; |
| 270 | } |
| 271 | |
| 272 | #if HAVE_VM_ALLOCATE |
| 273 | /*++ |
| 274 | Function: |
| 275 | UTIL_MachErrorToPalError |
| 276 | |
| 277 | Maps a Mach kern_return_t to a Win32 error code. |
| 278 | --*/ |
| 279 | DWORD UTIL_MachErrorToPalError(kern_return_t MachReturn) |
| 280 | { |
| 281 | switch (MachReturn) |
| 282 | { |
| 283 | case KERN_SUCCESS: |
| 284 | return ERROR_SUCCESS; |
| 285 | |
| 286 | case KERN_NO_ACCESS: |
| 287 | case KERN_INVALID_CAPABILITY: |
| 288 | return ERROR_ACCESS_DENIED; |
| 289 | |
| 290 | case KERN_TERMINATED: |
| 291 | return ERROR_INVALID_HANDLE; |
| 292 | |
| 293 | case KERN_INVALID_ADDRESS: |
| 294 | return ERROR_INVALID_ADDRESS; |
| 295 | |
| 296 | case KERN_NO_SPACE: |
| 297 | return ERROR_NOT_ENOUGH_MEMORY; |
| 298 | |
| 299 | case KERN_INVALID_ARGUMENT: |
| 300 | return ERROR_INVALID_PARAMETER; |
| 301 | |
| 302 | default: |
| 303 | ASSERT("Unknown kern_return_t value %d - reporting ERROR_INTERNAL_ERROR\n" , MachReturn); |
| 304 | return ERROR_INTERNAL_ERROR; |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | /*++ |
| 309 | Function: |
| 310 | UTIL_SetLastErrorFromMach |
| 311 | |
| 312 | Sets Win32 LastError according to the argument Mach kern_return_t value, |
| 313 | provided it indicates an error. If the argument indicates success, does |
| 314 | not modify LastError. |
| 315 | --*/ |
| 316 | void UTIL_SetLastErrorFromMach(kern_return_t MachReturn) |
| 317 | { |
| 318 | DWORD palError = UTIL_MachErrorToPalError(MachReturn); |
| 319 | if (palError != ERROR_SUCCESS) |
| 320 | { |
| 321 | SetLastError(palError); |
| 322 | } |
| 323 | } |
| 324 | #endif //HAVE_VM_ALLOCATE |
| 325 | |
| 326 | |