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).
adb_strerror(int err)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