diff options
author | Josh Gao <jmgao@google.com> | 2016-12-05 17:11:34 -0800 |
---|---|---|
committer | Josh Gao <jmgao@google.com> | 2016-12-05 17:38:30 -0800 |
commit | 5a1e3fdaf82aee348b1b22992a8c1d15db38413b (patch) | |
tree | 8b2b01f82b1f683fecee9b9bcd5a48ee28d6da6c | |
parent | a3577e1ac558d83428c492e806549e278e5dc8fb (diff) | |
download | system_core-5a1e3fdaf82aee348b1b22992a8c1d15db38413b.tar.gz system_core-5a1e3fdaf82aee348b1b22992a8c1d15db38413b.tar.bz2 system_core-5a1e3fdaf82aee348b1b22992a8c1d15db38413b.zip |
Revert "Revert "adb: extend sync protocol's stat support.""
This reverts commit afa4b5d6eb45bbee8671a1bb93ea70506fb326e3.
Add functions to translate errno to and from the linux asm-generic
values, since mips has different values.
Bug: http://b/33058958
Test: python test_device.py with both old and new adbd
Change-Id: I1a122235f3e793ed10b3bf3ad293388015134150
-rw-r--r-- | adb/Android.mk | 1 | ||||
-rw-r--r-- | adb/adb.h | 2 | ||||
-rw-r--r-- | adb/file_sync_client.cpp | 238 | ||||
-rw-r--r-- | adb/file_sync_service.cpp | 88 | ||||
-rw-r--r-- | adb/file_sync_service.h | 20 | ||||
-rw-r--r-- | adb/sysdeps/errno.cpp | 100 | ||||
-rw-r--r-- | adb/sysdeps/errno.h | 5 | ||||
-rw-r--r-- | adb/transport.cpp | 4 | ||||
-rw-r--r-- | adb/transport.h | 1 |
9 files changed, 363 insertions, 96 deletions
diff --git a/adb/Android.mk b/adb/Android.mk index f9998e4ec..16ed9911c 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -50,6 +50,7 @@ LIBADB_SRC_FILES := \ fdevent.cpp \ sockets.cpp \ socket_spec.cpp \ + sysdeps/errno.cpp \ transport.cpp \ transport_local.cpp \ transport_usb.cpp \ @@ -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 37 +#define ADB_SERVER_VERSION 38 class atransport; struct usb_handle; diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp index cf03160ee..76119efc4 100644 --- a/adb/file_sync_client.cpp +++ b/adb/file_sync_client.cpp @@ -41,6 +41,7 @@ #include "adb_utils.h" #include "file_sync_service.h" #include "line_printer.h" +#include "sysdeps/errno.h" #include "sysdeps/stat.h" #include <android-base/file.h> @@ -73,8 +74,8 @@ static bool should_push_file(mode_t mode) { struct copyinfo { std::string lpath; std::string rpath; - unsigned int time = 0; - unsigned int mode; + int64_t time = 0; + uint32_t mode; uint64_t size = 0; bool skip = false; @@ -201,9 +202,16 @@ class SyncConnection { max = SYNC_DATA_MAX; // TODO: decide at runtime. std::string error; - fd = adb_connect("sync:", &error); - if (fd < 0) { - Error("connect failed: %s", error.c_str()); + 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()); + } } } @@ -290,6 +298,77 @@ 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 = errno_from_wire(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, @@ -427,7 +506,7 @@ class SyncConnection { return false; } buf[msg.status.msglen] = 0; - Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]); + Error("failed to copy '%s' to '%s': remote %s", from, to, &buf[0]); return false; } @@ -498,6 +577,7 @@ class SyncConnection { private: bool expect_done_; + bool have_stat_v2_; TransferLedger global_ledger_; TransferLedger current_ledger_; @@ -553,25 +633,47 @@ static bool sync_ls(SyncConnection& sc, const char* path, } } -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) { +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) { return false; } - if (timestamp) *timestamp = msg.stat.time; - if (mode) *mode = msg.stat.mode; - if (size) *size = msg.stat.size; + // 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 (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) { @@ -619,8 +721,11 @@ 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) { - unsigned size = 0; - if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false; + 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; + } if (!sc.SendRequest(ID_RECV, rpath)) return false; @@ -673,7 +778,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, size); + sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, st.st_size); } sc.RecordFilesTransferred(1); @@ -776,20 +881,20 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, if (check_timestamps) { for (const copyinfo& ci : file_list) { - if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) { + if (!sc.SendLstat(ci.rpath.c_str())) { + sc.Error("failed to send lstat"); return false; } } for (copyinfo& ci : file_list) { - 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; + struct stat st; + if (sc.FinishStat(&st)) { + if (st.st_size == static_cast<off_t>(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; + } } } } @@ -821,10 +926,22 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { if (!sc.IsValid()) return false; bool success = true; - 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); + 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; + } + } if (!dst_isdir) { if (srcs.size() > 1) { @@ -869,8 +986,7 @@ bool do_sync_push(const std::vector<const char*>& 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); @@ -899,17 +1015,6 @@ bool do_sync_push(const std::vector<const char*>& 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<copyinfo>* file_list, const std::string& rpath, const std::string& lpath) { std::vector<copyinfo> dirlist; @@ -947,7 +1052,13 @@ static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_li // Check each symlink we found to see whether it's a file or directory. for (copyinfo& link_ci : linklist) { - if (remote_symlink_isdir(sc, link_ci.rpath)) { + 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)) { dirlist.emplace_back(std::move(link_ci)); } else { file_list->emplace_back(std::move(link_ci)); @@ -1073,22 +1184,19 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, for (const char* src_path : srcs) { const char* dst_path = dst; - 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); + 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)); + } + success = false; continue; } - bool src_isdir = S_ISDIR(src_mode); - if (S_ISLNK(src_mode)) { - src_isdir = remote_symlink_isdir(sc, src_path); - } - + bool src_isdir = S_ISDIR(src_st.st_mode); if (src_isdir) { std::string dst_dir = dst; @@ -1107,8 +1215,8 @@ bool do_sync_pull(const std::vector<const char*>& 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_mode)) { - sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_mode); + } else if (!should_pull_file(src_st.st_mode)) { + sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode); continue; } @@ -1123,13 +1231,13 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, } sc.NewTransfer(); - sc.SetExpectedTotalBytes(src_size); + sc.SetExpectedTotalBytes(src_st.st_size); if (!sync_recv(sc, src_path, dst_path, name)) { success = false; continue; } - if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) { + if (copy_attrs && set_time_and_mode(dst_path, src_st.st_mtime, src_st.st_mode) != 0) { success = false; continue; } diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp index 7a92d2ee4..43c877e27 100644 --- a/adb/file_sync_service.cpp +++ b/adb/file_sync_service.cpp @@ -41,6 +41,7 @@ #include "adb_io.h" #include "adb_utils.h" #include "security_log_tags.h" +#include "sysdeps/errno.h" static bool should_use_fs_config(const std::string& path) { // TODO: use fs_config to configure permissions on /data. @@ -98,18 +99,47 @@ static bool secure_mkdirs(const std::string& path) { return true; } -static bool do_stat(int s, const char* path) { - syncmsg msg; - msg.stat.id = ID_STAT; +static bool do_lstat_v1(int s, const char* path) { + syncmsg msg = {}; + msg.stat_v1.id = ID_LSTAT_V1; struct stat st = {}; - // TODO: add a way to report that the stat failed! lstat(path, &st); - msg.stat.mode = st.st_mode; - msg.stat.size = st.st_size; - msg.stat.time = st.st_mtime; + 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)); +} + +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_to_wire(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, sizeof(msg.stat)); + return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2)); } static bool do_list(int s, const char* path) { @@ -427,30 +457,34 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) { D("sync: '%.4s' '%s'", id, name); switch (request.id) { - 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; + 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; } return true; } -void file_sync_service(int fd, void* cookie) { +void file_sync_service(int fd, void*) { std::vector<char> 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 0e25974a1..90f1965df 100644 --- a/adb/file_sync_service.h +++ b/adb/file_sync_service.h @@ -22,7 +22,9 @@ #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) -#define ID_STAT MKID('S','T','A','T') +#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_LIST MKID('L','I','S','T') #define ID_SEND MKID('S','E','N','D') #define ID_RECV MKID('R','E','C','V') @@ -45,7 +47,21 @@ union syncmsg { uint32_t mode; uint32_t size; uint32_t time; - } stat; + } 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; struct __attribute__((packed)) { uint32_t id; uint32_t mode; diff --git a/adb/sysdeps/errno.cpp b/adb/sysdeps/errno.cpp new file mode 100644 index 000000000..68699476a --- /dev/null +++ b/adb/sysdeps/errno.cpp @@ -0,0 +1,100 @@ +/* + * 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 <errno.h> + +#include <thread> +#include <unordered_map> +#include <utility> + +#include "adb.h" + +#if defined(_WIN32) +#define ETXTBSY EBUSY +#endif + +// Use the linux asm-generic values for errno (which are used on all android archs but mips). +#define ERRNO_VALUES() \ + 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) + +// Make sure these values are actually correct. +#if defined(__linux__) && !defined(__mips__) +#define ERRNO_VALUE(error_name, wire_value) static_assert((error_name) == (wire_value), "") +ERRNO_VALUES(); +#undef ERRNO_VALUE +#endif + +static std::unordered_map<int, int>* generate_host_to_wire() { + auto result = new std::unordered_map<int, int>(); +#define ERRNO_VALUE(error_name, wire_value) \ + result->insert(std::make_pair((error_name), (wire_value))) + ERRNO_VALUES(); +#undef ERRNO_VALUE + return result; +} + +static std::unordered_map<int, int>* generate_wire_to_host() { + auto result = new std::unordered_map<int, int>(); +#define ERRNO_VALUE(error_name, wire_value) \ + result->insert(std::make_pair((wire_value), (error_name))) + ERRNO_VALUES(); +#undef ERRNO_VALUE + return result; +} + +static std::unordered_map<int, int>& host_to_wire = *generate_host_to_wire(); +static std::unordered_map<int, int>& wire_to_host = *generate_wire_to_host(); + +int errno_to_wire(int error) { + auto it = host_to_wire.find(error); + if (it == host_to_wire.end()) { + LOG(ERROR) << "failed to convert errno " << error << " (" << strerror(error) << ") to wire"; + + // Return EIO; + return 5; + } + return it->second; +} + +int errno_from_wire(int error) { + auto it = host_to_wire.find(error); + if (it == host_to_wire.end()) { + LOG(ERROR) << "failed to convert errno " << error << " from wire"; + return EIO; + } + return it->second; +} diff --git a/adb/sysdeps/errno.h b/adb/sysdeps/errno.h index e7e9841ec..72816b127 100644 --- a/adb/sysdeps/errno.h +++ b/adb/sysdeps/errno.h @@ -23,3 +23,8 @@ char* adb_strerror(int err); #define strerror adb_strerror #endif + +// errno values differ between operating systems and between Linux architectures. +// Arbitrarily select the Linux asm-generic values to use in the wire protocol. +int errno_to_wire(int error); +int errno_from_wire(int error); diff --git a/adb/transport.cpp b/adb/transport.cpp index 132702d31..7b82b197e 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -49,6 +49,7 @@ 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; @@ -771,7 +772,8 @@ const FeatureSet& supported_features() { // Local static allocation to avoid global non-POD variables. static const FeatureSet* features = new FeatureSet{ kFeatureShell2, - kFeatureCmd + kFeatureCmd, + kFeatureStat2, // 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 b2df838b6..330638829 100644 --- a/adb/transport.h +++ b/adb/transport.h @@ -46,6 +46,7 @@ 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: |