Merge changes Ie7becb64,I02ced540
* changes: Revert "adb: extend sync protocol's stat support." Revert "adb: move adb_strerror to sysdeps/win32/errno.cpp."
This commit is contained in:
commit
431e272251
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -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 <android-base/file.h>
|
||||
|
@ -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<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;
|
||||
}
|
||||
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<const char*>& 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<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);
|
||||
|
@ -1015,6 +901,17 @@ 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;
|
||||
|
@ -1052,13 +949,7 @@ 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) {
|
||||
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<const char*>& 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<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_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<const char*>& 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;
|
||||
}
|
||||
|
|
|
@ -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<char>& 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<char> buffer(SYNC_DATA_MAX);
|
||||
|
||||
while (handle_sync_command(fd, buffer)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include <android-base/unique_fd.h>
|
||||
#include <android-base/utf8.h>
|
||||
|
||||
#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 {
|
||||
|
|
|
@ -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 <errno.h>
|
||||
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "adb.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define ETXTBSY EBUSY
|
||||
#endif
|
||||
|
||||
static std::unordered_map<int, int> initialize_translations() {
|
||||
std::unordered_map<int, int> 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<int, int> translations = initialize_translations();
|
||||
auto it = translations.find(error);
|
||||
if (it != translations.end()) {
|
||||
return it->second;
|
||||
}
|
||||
fatal("received unexpected remote errno: %d", error);
|
||||
#endif
|
||||
}
|
|
@ -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 <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
// 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
|
|
@ -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 <windows.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// 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")
|
||||
}
|
|
@ -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 <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
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");
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue