Home | History | Annotate | Download | only in win32
      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