1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "sysdeps/errno.h" 18 19 #include <windows.h> 20 21 #include <string> 22 23 // Overrides strerror() to handle error codes not supported by the Windows C 24 // Runtime (MSVCRT.DLL). 25 char* adb_strerror(int err) { 26 // sysdeps.h defines strerror to adb_strerror, but in this function, we 27 // want to call the real C Runtime strerror(). 28 #pragma push_macro("strerror") 29 #undef strerror 30 const int saved_err = errno; // Save because we overwrite it later. 31 32 // Lookup the string for an unknown error. 33 char* errmsg = strerror(-1); 34 const std::string unknown_error = (errmsg == nullptr) ? "" : errmsg; 35 36 // Lookup the string for this error to see if the C Runtime has it. 37 errmsg = strerror(err); 38 if (errmsg != nullptr && unknown_error != errmsg) { 39 // The CRT returned an error message and it is different than the error 40 // message for an unknown error, so it is probably valid, so use it. 41 } else { 42 // Check if we have a string for this error code. 43 const char* custom_msg = nullptr; 44 switch (err) { 45 #pragma push_macro("ERR") 46 #undef ERR 47 #define ERR(errnum, desc) case errnum: custom_msg = desc; break 48 // These error strings are from AOSP bionic/libc/include/sys/_errdefs.h. 49 // Note that these cannot be longer than 94 characters because we 50 // pass this to _strerror() which has that requirement. 51 ERR(ECONNRESET, "Connection reset by peer"); 52 ERR(EHOSTUNREACH, "No route to host"); 53 ERR(ENETDOWN, "Network is down"); 54 ERR(ENETRESET, "Network dropped connection because of reset"); 55 ERR(ENOBUFS, "No buffer space available"); 56 ERR(ENOPROTOOPT, "Protocol not available"); 57 ERR(ENOTCONN, "Transport endpoint is not connected"); 58 ERR(ENOTSOCK, "Socket operation on non-socket"); 59 ERR(EOPNOTSUPP, "Operation not supported on transport endpoint"); 60 #pragma pop_macro("ERR") 61 } 62 63 if (custom_msg != nullptr) { 64 // Use _strerror() to write our string into the writable per-thread 65 // buffer used by strerror()/_strerror(). _strerror() appends the 66 // msg for the current value of errno, so set errno to a consistent 67 // value for every call so that our code-path is always the same. 68 errno = 0; 69 errmsg = _strerror(custom_msg); 70 const size_t custom_msg_len = strlen(custom_msg); 71 // Just in case _strerror() returned a read-only string, check if 72 // the returned string starts with our custom message because that 73 // implies that the string is not read-only. 74 if ((errmsg != nullptr) && !strncmp(custom_msg, errmsg, custom_msg_len)) { 75 // _strerror() puts other text after our custom message, so 76 // remove that by terminating after our message. 77 errmsg[custom_msg_len] = '\0'; 78 } else { 79 // For some reason nullptr was returned or a pointer to a 80 // read-only string was returned, so fallback to whatever 81 // strerror() can muster (probably "Unknown error" or some 82 // generic CRT error string). 83 errmsg = strerror(err); 84 } 85 } else { 86 // We don't have a custom message, so use whatever strerror(err) 87 // returned earlier. 88 } 89 } 90 91 errno = saved_err; // restore 92 93 return errmsg; 94 #pragma pop_macro("strerror") 95 } 96