diff --git a/adb/Android.mk b/adb/Android.mk index 16ed9911c..be04cfa10 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -50,7 +50,6 @@ LIBADB_SRC_FILES := \ fdevent.cpp \ sockets.cpp \ socket_spec.cpp \ - sysdeps/errno.cpp \ transport.cpp \ transport_local.cpp \ transport_usb.cpp \ @@ -89,12 +88,10 @@ LIBADB_linux_SRC_FILES := \ LIBADB_windows_SRC_FILES := \ sysdeps_win32.cpp \ - sysdeps/win32/errno.cpp \ sysdeps/win32/stat.cpp \ usb_windows.cpp \ LIBADB_TEST_windows_SRCS := \ - sysdeps/win32/errno_test.cpp \ sysdeps_win32_test.cpp \ include $(CLEAR_VARS) diff --git a/adb/adb.h b/adb/adb.h index 19f09a308..df59aaaa9 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -51,7 +51,7 @@ constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2; std::string adb_version(); // Increment this when we want to force users to start a new adb server. -#define ADB_SERVER_VERSION 38 +#define ADB_SERVER_VERSION 37 class atransport; struct usb_handle; diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp index 516056972..caa7a5f6b 100644 --- a/adb/file_sync_client.cpp +++ b/adb/file_sync_client.cpp @@ -15,10 +15,12 @@ */ #include +#include #include #include #include #include +#include #include #include #include @@ -41,7 +43,6 @@ #include "adb_utils.h" #include "file_sync_service.h" #include "line_printer.h" -#include "sysdeps/errno.h" #include "sysdeps/stat.h" #include @@ -74,8 +75,8 @@ static bool should_push_file(mode_t mode) { struct copyinfo { std::string lpath; std::string rpath; - int64_t time = 0; - uint32_t mode; + unsigned int time = 0; + unsigned int mode; uint64_t size = 0; bool skip = false; @@ -202,16 +203,9 @@ class SyncConnection { max = SYNC_DATA_MAX; // TODO: decide at runtime. std::string error; - FeatureSet features; - if (!adb_get_feature_set(&features, &error)) { - fd = -1; - Error("failed to get feature set: %s", error.c_str()); - } else { - have_stat_v2_ = CanUseFeature(features, kFeatureStat2); - fd = adb_connect("sync:", &error); - if (fd < 0) { - Error("connect failed: %s", error.c_str()); - } + fd = adb_connect("sync:", &error); + if (fd < 0) { + Error("connect failed: %s", error.c_str()); } } @@ -298,77 +292,6 @@ class SyncConnection { return WriteFdExactly(fd, &buf[0], buf.size()); } - bool SendStat(const char* path_and_mode) { - if (!have_stat_v2_) { - errno = ENOTSUP; - return false; - } - return SendRequest(ID_STAT_V2, path_and_mode); - } - - bool SendLstat(const char* path_and_mode) { - if (have_stat_v2_) { - return SendRequest(ID_LSTAT_V2, path_and_mode); - } else { - return SendRequest(ID_LSTAT_V1, path_and_mode); - } - } - - bool FinishStat(struct stat* st) { - syncmsg msg; - - memset(st, 0, sizeof(*st)); - if (have_stat_v2_) { - if (!ReadFdExactly(fd, &msg.stat_v2, sizeof(msg.stat_v2))) { - fatal_errno("protocol fault: failed to read stat response"); - } - - if (msg.stat_v2.id != ID_LSTAT_V2 && msg.stat_v2.id != ID_STAT_V2) { - fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32, - msg.stat_v2.id); - } - - if (msg.stat_v2.error != 0) { - errno = translate_linux_errno(msg.stat_v2.error); - return false; - } - - st->st_dev = msg.stat_v2.dev; - st->st_ino = msg.stat_v2.ino; - st->st_mode = msg.stat_v2.mode; - st->st_nlink = msg.stat_v2.nlink; - st->st_uid = msg.stat_v2.uid; - st->st_gid = msg.stat_v2.gid; - st->st_size = msg.stat_v2.size; - st->st_atime = msg.stat_v2.atime; - st->st_mtime = msg.stat_v2.mtime; - st->st_ctime = msg.stat_v2.ctime; - return true; - } else { - if (!ReadFdExactly(fd, &msg.stat_v1, sizeof(msg.stat_v1))) { - fatal_errno("protocol fault: failed to read stat response"); - } - - if (msg.stat_v1.id != ID_LSTAT_V1) { - fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32, - msg.stat_v1.id); - } - - if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) { - // There's no way for us to know what the error was. - errno = ENOPROTOOPT; - return false; - } - - st->st_mode = msg.stat_v1.mode; - st->st_size = msg.stat_v1.size; - st->st_ctime = msg.stat_v1.time; - st->st_mtime = msg.stat_v1.time; - } - - return true; - } - // Sending header, payload, and footer in a single write makes a huge // difference to "adb sync" performance. bool SendSmallFile(const char* path_and_mode, @@ -506,7 +429,7 @@ class SyncConnection { return false; } buf[msg.status.msglen] = 0; - Error("failed to copy '%s' to '%s': remote %s", from, to, &buf[0]); + Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]); return false; } @@ -577,7 +500,6 @@ class SyncConnection { private: bool expect_done_; - bool have_stat_v2_; TransferLedger global_ledger_; TransferLedger current_ledger_; @@ -633,47 +555,25 @@ static bool sync_ls(SyncConnection& sc, const char* path, } } -static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) { - return sc.SendStat(path) && sc.FinishStat(st); -} - -static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) { - return sc.SendLstat(path) && sc.FinishStat(st); -} - -static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) { - if (sync_stat(sc, path, st)) { - return true; - } - - if (errno != ENOTSUP) { +static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp, + unsigned int* mode, unsigned int* size) { + syncmsg msg; + if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) { return false; } - // Try to emulate the parts we can when talking to older adbds. - bool lstat_result = sync_lstat(sc, path, st); - if (!lstat_result) { - return false; - } + if (timestamp) *timestamp = msg.stat.time; + if (mode) *mode = msg.stat.mode; + if (size) *size = msg.stat.size; - if (S_ISLNK(st->st_mode)) { - // If the target is a symlink, figure out whether it's a file or a directory. - // Also, zero out the st_size field, since no one actually cares what the path length is. - st->st_size = 0; - std::string dir_path = path; - dir_path.push_back('/'); - struct stat tmp_st; - - st->st_mode &= ~S_IFMT; - if (sync_lstat(sc, dir_path.c_str(), &tmp_st)) { - st->st_mode |= S_IFDIR; - } else { - st->st_mode |= S_IFREG; - } - } return true; } +static bool sync_stat(SyncConnection& sc, const char* path, + unsigned int* timestamp, unsigned int* mode, unsigned int* size) { + return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size); +} + static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime, mode_t mode) { @@ -721,11 +621,8 @@ static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, const char* name=nullptr) { - struct stat st; - if (!sync_stat_fallback(sc, rpath, &st)) { - sc.Error("stat failed when trying to receive %s: %s", rpath, strerror(errno)); - return false; - } + unsigned size = 0; + if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false; if (!sc.SendRequest(ID_RECV, rpath)) return false; @@ -778,7 +675,7 @@ static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bytes_copied += msg.data.size; sc.RecordBytesTransferred(msg.data.size); - sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, st.st_size); + sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, size); } sc.RecordFilesTransferred(1); @@ -881,20 +778,20 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, if (check_timestamps) { for (const copyinfo& ci : file_list) { - if (!sc.SendLstat(ci.rpath.c_str())) { - sc.Error("failed to send lstat"); + if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) { return false; } } for (copyinfo& ci : file_list) { - struct stat st; - if (sc.FinishStat(&st)) { - if (st.st_size == static_cast(ci.size)) { - // For links, we cannot update the atime/mtime. - if ((S_ISREG(ci.mode & st.st_mode) && st.st_mtime == ci.time) || - (S_ISLNK(ci.mode & st.st_mode) && st.st_mtime >= ci.time)) { - ci.skip = true; - } + unsigned int timestamp, mode, size; + if (!sync_finish_stat(sc, ×tamp, &mode, &size)) { + return false; + } + if (size == ci.size) { + // For links, we cannot update the atime/mtime. + if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) || + (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) { + ci.skip = true; } } } @@ -926,22 +823,10 @@ bool do_sync_push(const std::vector& srcs, const char* dst) { if (!sc.IsValid()) return false; bool success = true; - bool dst_exists; - bool dst_isdir; - - struct stat st; - if (sync_stat_fallback(sc, dst, &st)) { - dst_exists = true; - dst_isdir = S_ISDIR(st.st_mode); - } else { - if (errno == ENOENT || errno == ENOPROTOOPT) { - dst_exists = false; - dst_isdir = false; - } else { - sc.Error("stat failed when trying to push to %s: %s", dst, strerror(errno)); - return false; - } - } + unsigned dst_mode; + if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false; + bool dst_exists = (dst_mode != 0); + bool dst_isdir = S_ISDIR(dst_mode); if (!dst_isdir) { if (srcs.size() > 1) { @@ -986,7 +871,8 @@ bool do_sync_push(const std::vector& srcs, const char* dst) { dst_dir.append(adb_basename(src_path)); } - success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), false, false); + success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), + false, false); continue; } else if (!should_push_file(st.st_mode)) { sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode); @@ -1015,6 +901,17 @@ bool do_sync_push(const std::vector& srcs, const char* dst) { return success; } +static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) { + unsigned mode; + std::string dir_path = rpath; + dir_path.push_back('/'); + if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) { + sc.Error("failed to stat remote symlink '%s'", dir_path.c_str()); + return false; + } + return S_ISDIR(mode); +} + static bool remote_build_list(SyncConnection& sc, std::vector* file_list, const std::string& rpath, const std::string& lpath) { std::vector dirlist; @@ -1052,13 +949,7 @@ static bool remote_build_list(SyncConnection& sc, std::vector* file_li // Check each symlink we found to see whether it's a file or directory. for (copyinfo& link_ci : linklist) { - struct stat st; - if (!sync_stat_fallback(sc, link_ci.rpath.c_str(), &st)) { - sc.Warning("stat failed for path %s: %s", link_ci.rpath.c_str(), strerror(errno)); - continue; - } - - if (S_ISDIR(st.st_mode)) { + if (remote_symlink_isdir(sc, link_ci.rpath)) { dirlist.emplace_back(std::move(link_ci)); } else { file_list->emplace_back(std::move(link_ci)); @@ -1184,19 +1075,22 @@ bool do_sync_pull(const std::vector& srcs, const char* dst, for (const char* src_path : srcs) { const char* dst_path = dst; - struct stat src_st; - if (!sync_stat_fallback(sc, src_path, &src_st)) { - if (errno == ENOPROTOOPT) { - sc.Error("remote object '%s' does not exist", src_path); - } else { - sc.Error("failed to stat remote object '%s': %s", src_path, strerror(errno)); - } - + unsigned src_mode, src_time, src_size; + if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) { + sc.Error("failed to stat remote object '%s'", src_path); + return false; + } + if (src_mode == 0) { + sc.Error("remote object '%s' does not exist", src_path); success = false; continue; } - bool src_isdir = S_ISDIR(src_st.st_mode); + bool src_isdir = S_ISDIR(src_mode); + if (S_ISLNK(src_mode)) { + src_isdir = remote_symlink_isdir(sc, src_path); + } + if (src_isdir) { std::string dst_dir = dst; @@ -1215,8 +1109,8 @@ bool do_sync_pull(const std::vector& srcs, const char* dst, success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs); continue; - } else if (!should_pull_file(src_st.st_mode)) { - sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode); + } else if (!should_pull_file(src_mode)) { + sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_mode); continue; } @@ -1231,13 +1125,13 @@ bool do_sync_pull(const std::vector& srcs, const char* dst, } sc.NewTransfer(); - sc.SetExpectedTotalBytes(src_st.st_size); + sc.SetExpectedTotalBytes(src_size); if (!sync_recv(sc, src_path, dst_path, name)) { success = false; continue; } - if (copy_attrs && set_time_and_mode(dst_path, src_st.st_mtime, src_st.st_mode) != 0) { + if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) { success = false; continue; } diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp index 57a8a452e..7a92d2ee4 100644 --- a/adb/file_sync_service.cpp +++ b/adb/file_sync_service.cpp @@ -98,47 +98,18 @@ static bool secure_mkdirs(const std::string& path) { return true; } -static bool do_lstat_v1(int s, const char* path) { - syncmsg msg = {}; - msg.stat_v1.id = ID_LSTAT_V1; +static bool do_stat(int s, const char* path) { + syncmsg msg; + msg.stat.id = ID_STAT; struct stat st = {}; + // TODO: add a way to report that the stat failed! lstat(path, &st); - msg.stat_v1.mode = st.st_mode; - msg.stat_v1.size = st.st_size; - msg.stat_v1.time = st.st_mtime; - return WriteFdExactly(s, &msg.stat_v1, sizeof(msg.stat_v1)); -} + msg.stat.mode = st.st_mode; + msg.stat.size = st.st_size; + msg.stat.time = st.st_mtime; -static bool do_stat_v2(int s, uint32_t id, const char* path) { - syncmsg msg = {}; - msg.stat_v2.id = id; - - decltype(&stat) stat_fn; - if (id == ID_STAT_V2) { - stat_fn = stat; - } else { - stat_fn = lstat; - } - - struct stat st = {}; - int rc = stat_fn(path, &st); - if (rc == -1) { - msg.stat_v2.error = errno; - } else { - msg.stat_v2.dev = st.st_dev; - msg.stat_v2.ino = st.st_ino; - msg.stat_v2.mode = st.st_mode; - msg.stat_v2.nlink = st.st_nlink; - msg.stat_v2.uid = st.st_uid; - msg.stat_v2.gid = st.st_gid; - msg.stat_v2.size = st.st_size; - msg.stat_v2.atime = st.st_atime; - msg.stat_v2.mtime = st.st_mtime; - msg.stat_v2.ctime = st.st_ctime; - } - - return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2)); + return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)); } static bool do_list(int s, const char* path) { @@ -456,34 +427,30 @@ static bool handle_sync_command(int fd, std::vector& buffer) { D("sync: '%.4s' '%s'", id, name); switch (request.id) { - case ID_LSTAT_V1: - if (!do_lstat_v1(fd, name)) return false; - break; - case ID_LSTAT_V2: - case ID_STAT_V2: - if (!do_stat_v2(fd, request.id, name)) return false; - break; - case ID_LIST: - if (!do_list(fd, name)) return false; - break; - case ID_SEND: - if (!do_send(fd, name, buffer)) return false; - break; - case ID_RECV: - if (!do_recv(fd, name, buffer)) return false; - break; - case ID_QUIT: - return false; - default: - SendSyncFail( - fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", id, request.id)); - return false; + case ID_STAT: + if (!do_stat(fd, name)) return false; + break; + case ID_LIST: + if (!do_list(fd, name)) return false; + break; + case ID_SEND: + if (!do_send(fd, name, buffer)) return false; + break; + case ID_RECV: + if (!do_recv(fd, name, buffer)) return false; + break; + case ID_QUIT: + return false; + default: + SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", + id, request.id)); + return false; } return true; } -void file_sync_service(int fd, void*) { +void file_sync_service(int fd, void* cookie) { std::vector buffer(SYNC_DATA_MAX); while (handle_sync_command(fd, buffer)) { diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h index 90f1965df..0e25974a1 100644 --- a/adb/file_sync_service.h +++ b/adb/file_sync_service.h @@ -22,9 +22,7 @@ #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) -#define ID_LSTAT_V1 MKID('S','T','A','T') -#define ID_STAT_V2 MKID('S','T','A','2') -#define ID_LSTAT_V2 MKID('L','S','T','2') +#define ID_STAT MKID('S','T','A','T') #define ID_LIST MKID('L','I','S','T') #define ID_SEND MKID('S','E','N','D') #define ID_RECV MKID('R','E','C','V') @@ -47,21 +45,7 @@ union syncmsg { uint32_t mode; uint32_t size; uint32_t time; - } stat_v1; - struct __attribute__((packed)) { - uint32_t id; - uint32_t error; - uint64_t dev; - uint64_t ino; - uint32_t mode; - uint32_t nlink; - uint32_t uid; - uint32_t gid; - uint64_t size; - int64_t atime; - int64_t mtime; - int64_t ctime; - } stat_v2; + } stat; struct __attribute__((packed)) { uint32_t id; uint32_t mode; diff --git a/adb/sysdeps.h b/adb/sysdeps.h index 654072c35..05d9fded1 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -34,7 +34,6 @@ #include #include -#include "sysdeps/errno.h" #include "sysdeps/stat.h" /* @@ -362,6 +361,9 @@ inline void seekdir(DIR*, long) { #define getcwd adb_getcwd +char* adb_strerror(int err); +#define strerror adb_strerror + // Helper class to convert UTF-16 argv from wmain() to UTF-8 args that can be // passed to main(). class NarrowArgs { diff --git a/adb/sysdeps/errno.cpp b/adb/sysdeps/errno.cpp deleted file mode 100644 index 0f7f58ad6..000000000 --- a/adb/sysdeps/errno.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sysdeps/errno.h" - -#include - -#include -#include - -#include "adb.h" - -#if defined(_WIN32) -#define ETXTBSY EBUSY -#endif - -static std::unordered_map initialize_translations() { - std::unordered_map translations; -#if defined(__linux__) -#define ERRNO_VALUE(error_name, linux_value) static_assert((error_name) == (linux_value), "") -#else -#define ERRNO_VALUE(error_name, linux_value) \ - translations.insert(std::make_pair((linux_value), (error_name))) -#endif - // Untranslated errno values returned by open: EDQUOT, ENODEV, ENXIO, EWOULDBLOCK - ERRNO_VALUE(EACCES, 13); - ERRNO_VALUE(EEXIST, 17); - ERRNO_VALUE(EFAULT, 14); - ERRNO_VALUE(EFBIG, 27); - ERRNO_VALUE(EINTR, 4); - ERRNO_VALUE(EINVAL, 22); - ERRNO_VALUE(EIO, 5); - ERRNO_VALUE(EISDIR, 21); - ERRNO_VALUE(ELOOP, 40); - ERRNO_VALUE(EMFILE, 24); - ERRNO_VALUE(ENAMETOOLONG, 36); - ERRNO_VALUE(ENFILE, 23); - ERRNO_VALUE(ENOENT, 2); - ERRNO_VALUE(ENOMEM, 12); - ERRNO_VALUE(ENOSPC, 28); - ERRNO_VALUE(ENOTDIR, 20); - ERRNO_VALUE(EOVERFLOW, 75); - ERRNO_VALUE(EPERM, 1); - ERRNO_VALUE(EROFS, 30); - ERRNO_VALUE(ETXTBSY, 26); - return translations; -} - -int translate_linux_errno(int error) { -#if defined(__linux__) - UNUSED(initialize_translations); - return error; -#else - static std::unordered_map translations = initialize_translations(); - auto it = translations.find(error); - if (it != translations.end()) { - return it->second; - } - fatal("received unexpected remote errno: %d", error); -#endif -} diff --git a/adb/sysdeps/errno.h b/adb/sysdeps/errno.h deleted file mode 100644 index f783b3a2f..000000000 --- a/adb/sysdeps/errno.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -// Translate an errno value from linux to the host equivalent. -int translate_linux_errno(int error); - -#if defined(_WIN32) -char* adb_strerror(int err); -#define strerror adb_strerror -#endif diff --git a/adb/sysdeps/win32/errno.cpp b/adb/sysdeps/win32/errno.cpp deleted file mode 100644 index a3b9d9b97..000000000 --- a/adb/sysdeps/win32/errno.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sysdeps/errno.h" - -#include - -#include - -// Overrides strerror() to handle error codes not supported by the Windows C -// Runtime (MSVCRT.DLL). -char* adb_strerror(int err) { -// sysdeps.h defines strerror to adb_strerror, but in this function, we -// want to call the real C Runtime strerror(). -#pragma push_macro("strerror") -#undef strerror - const int saved_err = errno; // Save because we overwrite it later. - - // Lookup the string for an unknown error. - char* errmsg = strerror(-1); - const std::string unknown_error = (errmsg == nullptr) ? "" : errmsg; - - // Lookup the string for this error to see if the C Runtime has it. - errmsg = strerror(err); - if (errmsg != nullptr && unknown_error != errmsg) { - // The CRT returned an error message and it is different than the error - // message for an unknown error, so it is probably valid, so use it. - } else { - // Check if we have a string for this error code. - const char* custom_msg = nullptr; - switch (err) { -#pragma push_macro("ERR") -#undef ERR -#define ERR(errnum, desc) case errnum: custom_msg = desc; break - // These error strings are from AOSP bionic/libc/include/sys/_errdefs.h. - // Note that these cannot be longer than 94 characters because we - // pass this to _strerror() which has that requirement. - ERR(ECONNRESET, "Connection reset by peer"); - ERR(EHOSTUNREACH, "No route to host"); - ERR(ENETDOWN, "Network is down"); - ERR(ENETRESET, "Network dropped connection because of reset"); - ERR(ENOBUFS, "No buffer space available"); - ERR(ENOPROTOOPT, "Protocol not available"); - ERR(ENOTCONN, "Transport endpoint is not connected"); - ERR(ENOTSOCK, "Socket operation on non-socket"); - ERR(EOPNOTSUPP, "Operation not supported on transport endpoint"); -#pragma pop_macro("ERR") - } - - if (custom_msg != nullptr) { - // Use _strerror() to write our string into the writable per-thread - // buffer used by strerror()/_strerror(). _strerror() appends the - // msg for the current value of errno, so set errno to a consistent - // value for every call so that our code-path is always the same. - errno = 0; - errmsg = _strerror(custom_msg); - const size_t custom_msg_len = strlen(custom_msg); - // Just in case _strerror() returned a read-only string, check if - // the returned string starts with our custom message because that - // implies that the string is not read-only. - if ((errmsg != nullptr) && !strncmp(custom_msg, errmsg, custom_msg_len)) { - // _strerror() puts other text after our custom message, so - // remove that by terminating after our message. - errmsg[custom_msg_len] = '\0'; - } else { - // For some reason nullptr was returned or a pointer to a - // read-only string was returned, so fallback to whatever - // strerror() can muster (probably "Unknown error" or some - // generic CRT error string). - errmsg = strerror(err); - } - } else { - // We don't have a custom message, so use whatever strerror(err) - // returned earlier. - } - } - - errno = saved_err; // restore - - return errmsg; -#pragma pop_macro("strerror") -} diff --git a/adb/sysdeps/win32/errno_test.cpp b/adb/sysdeps/win32/errno_test.cpp deleted file mode 100644 index 09ec52c86..000000000 --- a/adb/sysdeps/win32/errno_test.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sysdeps/errno.h" - -#include - -#include - -void TestAdbStrError(int err, const char* expected) { - errno = 12345; - const char* result = adb_strerror(err); - // Check that errno is not overwritten. - EXPECT_EQ(12345, errno); - EXPECT_STREQ(expected, result); -} - -TEST(sysdeps_win32, adb_strerror) { - // Test an error code that should not have a mapped string. Use an error - // code that is not used by the internal implementation of adb_strerror(). - TestAdbStrError(-2, "Unknown error"); - // adb_strerror() uses -1 internally, so test that it can still be passed - // as a parameter. - TestAdbStrError(-1, "Unknown error"); - // Test very big, positive unknown error. - TestAdbStrError(1000000, "Unknown error"); - - // Test success case. - // Wine returns "Success" for strerror(0), Windows returns "No error", so accept both. - std::string success = adb_strerror(0); - EXPECT_TRUE(success == "Success" || success == "No error") << "strerror(0) = " << success; - - // Test error that regular strerror() should have a string for. - TestAdbStrError(EPERM, "Operation not permitted"); - // Test error that regular strerror() doesn't have a string for, but that - // adb_strerror() returns. - TestAdbStrError(ECONNRESET, "Connection reset by peer"); -} diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp index a4b5e6978..4dd549dbd 100644 --- a/adb/sysdeps_win32.cpp +++ b/adb/sysdeps_win32.cpp @@ -477,6 +477,81 @@ int adb_close(int fd) return 0; } +// Overrides strerror() to handle error codes not supported by the Windows C +// Runtime (MSVCRT.DLL). +char* adb_strerror(int err) { + // sysdeps.h defines strerror to adb_strerror, but in this function, we + // want to call the real C Runtime strerror(). +#pragma push_macro("strerror") +#undef strerror + const int saved_err = errno; // Save because we overwrite it later. + + // Lookup the string for an unknown error. + char* errmsg = strerror(-1); + const std::string unknown_error = (errmsg == nullptr) ? "" : errmsg; + + // Lookup the string for this error to see if the C Runtime has it. + errmsg = strerror(err); + if (errmsg != nullptr && unknown_error != errmsg) { + // The CRT returned an error message and it is different than the error + // message for an unknown error, so it is probably valid, so use it. + } else { + // Check if we have a string for this error code. + const char* custom_msg = nullptr; + switch (err) { +#pragma push_macro("ERR") +#undef ERR +#define ERR(errnum, desc) case errnum: custom_msg = desc; break + // These error strings are from AOSP bionic/libc/include/sys/_errdefs.h. + // Note that these cannot be longer than 94 characters because we + // pass this to _strerror() which has that requirement. + ERR(ECONNRESET, "Connection reset by peer"); + ERR(EHOSTUNREACH, "No route to host"); + ERR(ENETDOWN, "Network is down"); + ERR(ENETRESET, "Network dropped connection because of reset"); + ERR(ENOBUFS, "No buffer space available"); + ERR(ENOPROTOOPT, "Protocol not available"); + ERR(ENOTCONN, "Transport endpoint is not connected"); + ERR(ENOTSOCK, "Socket operation on non-socket"); + ERR(EOPNOTSUPP, "Operation not supported on transport endpoint"); +#pragma pop_macro("ERR") + } + + if (custom_msg != nullptr) { + // Use _strerror() to write our string into the writable per-thread + // buffer used by strerror()/_strerror(). _strerror() appends the + // msg for the current value of errno, so set errno to a consistent + // value for every call so that our code-path is always the same. + errno = 0; + errmsg = _strerror(custom_msg); + const size_t custom_msg_len = strlen(custom_msg); + // Just in case _strerror() returned a read-only string, check if + // the returned string starts with our custom message because that + // implies that the string is not read-only. + if ((errmsg != nullptr) && + !strncmp(custom_msg, errmsg, custom_msg_len)) { + // _strerror() puts other text after our custom message, so + // remove that by terminating after our message. + errmsg[custom_msg_len] = '\0'; + } else { + // For some reason nullptr was returned or a pointer to a + // read-only string was returned, so fallback to whatever + // strerror() can muster (probably "Unknown error" or some + // generic CRT error string). + errmsg = strerror(err); + } + } else { + // We don't have a custom message, so use whatever strerror(err) + // returned earlier. + } + } + + errno = saved_err; // restore + + return errmsg; +#pragma pop_macro("strerror") +} + /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -490,7 +565,7 @@ int adb_close(int fd) static void _socket_set_errno( const DWORD err ) { // Because the Windows C Runtime (MSVCRT.DLL) strerror() does not support a // lot of POSIX and socket error codes, some of the resulting error codes - // are mapped to strings by adb_strerror(). + // are mapped to strings by adb_strerror() above. switch ( err ) { case 0: errno = 0; break; // Don't map WSAEINTR since that is only for Winsock 1.1 which we don't use. diff --git a/adb/sysdeps_win32_test.cpp b/adb/sysdeps_win32_test.cpp index 529b21215..c3a3fd7c1 100755 --- a/adb/sysdeps_win32_test.cpp +++ b/adb/sysdeps_win32_test.cpp @@ -70,6 +70,36 @@ TEST(sysdeps_win32, adb_getenv) { } } +void TestAdbStrError(int err, const char* expected) { + errno = 12345; + const char* result = adb_strerror(err); + // Check that errno is not overwritten. + EXPECT_EQ(12345, errno); + EXPECT_STREQ(expected, result); +} + +TEST(sysdeps_win32, adb_strerror) { + // Test an error code that should not have a mapped string. Use an error + // code that is not used by the internal implementation of adb_strerror(). + TestAdbStrError(-2, "Unknown error"); + // adb_strerror() uses -1 internally, so test that it can still be passed + // as a parameter. + TestAdbStrError(-1, "Unknown error"); + // Test very big, positive unknown error. + TestAdbStrError(1000000, "Unknown error"); + + // Test success case. + // Wine returns "Success" for strerror(0), Windows returns "No error", so accept both. + std::string success = adb_strerror(0); + EXPECT_TRUE(success == "Success" || success == "No error") << "strerror(0) = " << success; + + // Test error that regular strerror() should have a string for. + TestAdbStrError(EPERM, "Operation not permitted"); + // Test error that regular strerror() doesn't have a string for, but that + // adb_strerror() returns. + TestAdbStrError(ECONNRESET, "Connection reset by peer"); +} + TEST(sysdeps_win32, unix_isatty) { // stdin and stdout should be consoles. Use CONIN$ and CONOUT$ special files // so that we can test this even if stdin/stdout have been redirected. Read diff --git a/adb/transport.cpp b/adb/transport.cpp index 7b82b197e..132702d31 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -49,7 +49,6 @@ static std::mutex& transport_lock = *new std::mutex(); const char* const kFeatureShell2 = "shell_v2"; const char* const kFeatureCmd = "cmd"; -const char* const kFeatureStat2 = "stat_v2"; static std::string dump_packet(const char* name, const char* func, apacket* p) { unsigned command = p->msg.command; @@ -772,8 +771,7 @@ const FeatureSet& supported_features() { // Local static allocation to avoid global non-POD variables. static const FeatureSet* features = new FeatureSet{ kFeatureShell2, - kFeatureCmd, - kFeatureStat2, + kFeatureCmd // Increment ADB_SERVER_VERSION whenever the feature list changes to // make sure that the adb client and server features stay in sync // (http://b/24370690). diff --git a/adb/transport.h b/adb/transport.h index 330638829..b2df838b6 100644 --- a/adb/transport.h +++ b/adb/transport.h @@ -46,7 +46,6 @@ bool CanUseFeature(const FeatureSet& feature_set, const std::string& feature); extern const char* const kFeatureShell2; // The 'cmd' command is available extern const char* const kFeatureCmd; -extern const char* const kFeatureStat2; class atransport { public: