Loading adb/Android.mk +1 −0 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ LIBADB_SRC_FILES := \ fdevent.cpp \ fdevent.cpp \ sockets.cpp \ sockets.cpp \ socket_spec.cpp \ socket_spec.cpp \ sysdeps/errno.cpp \ transport.cpp \ transport.cpp \ transport_local.cpp \ transport_local.cpp \ transport_usb.cpp \ transport_usb.cpp \ Loading adb/adb.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -51,7 +51,7 @@ constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2; std::string adb_version(); std::string adb_version(); // Increment this when we want to force users to start a new adb server. // 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; class atransport; struct usb_handle; struct usb_handle; Loading adb/file_sync_client.cpp +173 −65 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include "adb_utils.h" #include "adb_utils.h" #include "file_sync_service.h" #include "file_sync_service.h" #include "line_printer.h" #include "line_printer.h" #include "sysdeps/errno.h" #include "sysdeps/stat.h" #include "sysdeps/stat.h" #include <android-base/file.h> #include <android-base/file.h> Loading Loading @@ -73,8 +74,8 @@ static bool should_push_file(mode_t mode) { struct copyinfo { struct copyinfo { std::string lpath; std::string lpath; std::string rpath; std::string rpath; unsigned int time = 0; int64_t time = 0; unsigned int mode; uint32_t mode; uint64_t size = 0; uint64_t size = 0; bool skip = false; bool skip = false; Loading Loading @@ -201,11 +202,18 @@ class SyncConnection { max = SYNC_DATA_MAX; // TODO: decide at runtime. max = SYNC_DATA_MAX; // TODO: decide at runtime. std::string error; 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); fd = adb_connect("sync:", &error); if (fd < 0) { if (fd < 0) { Error("connect failed: %s", error.c_str()); Error("connect failed: %s", error.c_str()); } } } } } ~SyncConnection() { ~SyncConnection() { if (!IsValid()) return; if (!IsValid()) return; Loading Loading @@ -290,6 +298,77 @@ class SyncConnection { return WriteFdExactly(fd, &buf[0], buf.size()); 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 // Sending header, payload, and footer in a single write makes a huge // difference to "adb sync" performance. // difference to "adb sync" performance. bool SendSmallFile(const char* path_and_mode, bool SendSmallFile(const char* path_and_mode, Loading Loading @@ -427,7 +506,7 @@ class SyncConnection { return false; return false; } } buf[msg.status.msglen] = 0; 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; return false; } } Loading Loading @@ -498,6 +577,7 @@ class SyncConnection { private: private: bool expect_done_; bool expect_done_; bool have_stat_v2_; TransferLedger global_ledger_; TransferLedger global_ledger_; TransferLedger current_ledger_; TransferLedger current_ledger_; Loading Loading @@ -553,23 +633,45 @@ static bool sync_ls(SyncConnection& sc, const char* path, } } } } static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp, static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) { unsigned int* mode, unsigned int* size) { return sc.SendStat(path) && sc.FinishStat(st); syncmsg msg; if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) { return false; } } if (timestamp) *timestamp = msg.stat.time; static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) { if (mode) *mode = msg.stat.mode; return sc.SendLstat(path) && sc.FinishStat(st); if (size) *size = msg.stat.size; } static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) { if (sync_stat(sc, path, st)) { return true; return true; } } static bool sync_stat(SyncConnection& sc, const char* path, if (errno != ENOTSUP) { unsigned int* timestamp, unsigned int* mode, unsigned int* size) { return false; return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, 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_send(SyncConnection& sc, const char* lpath, const char* rpath, static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, Loading Loading @@ -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, static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, const char* name=nullptr) { const char* name=nullptr) { unsigned size = 0; struct stat st; if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false; 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; if (!sc.SendRequest(ID_RECV, rpath)) return false; Loading Loading @@ -673,7 +778,7 @@ static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bytes_copied += msg.data.size; bytes_copied += msg.data.size; sc.RecordBytesTransferred(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); sc.RecordFilesTransferred(1); Loading Loading @@ -776,24 +881,24 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, if (check_timestamps) { if (check_timestamps) { for (const copyinfo& ci : file_list) { 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; return false; } } } } for (copyinfo& ci : file_list) { for (copyinfo& ci : file_list) { unsigned int timestamp, mode, size; struct stat st; if (!sync_finish_stat(sc, ×tamp, &mode, &size)) { if (sc.FinishStat(&st)) { return false; if (st.st_size == static_cast<off_t>(ci.size)) { } if (size == ci.size) { // For links, we cannot update the atime/mtime. // For links, we cannot update the atime/mtime. if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) || if ((S_ISREG(ci.mode & st.st_mode) && st.st_mtime == ci.time) || (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) { (S_ISLNK(ci.mode & st.st_mode) && st.st_mtime >= ci.time)) { ci.skip = true; ci.skip = true; } } } } } } } } } sc.ComputeExpectedTotalBytes(file_list); sc.ComputeExpectedTotalBytes(file_list); Loading Loading @@ -821,10 +926,22 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { if (!sc.IsValid()) return false; if (!sc.IsValid()) return false; bool success = true; bool success = true; unsigned dst_mode; bool dst_exists; if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false; bool dst_isdir; bool dst_exists = (dst_mode != 0); bool dst_isdir = S_ISDIR(dst_mode); 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 (!dst_isdir) { if (srcs.size() > 1) { if (srcs.size() > 1) { Loading Loading @@ -869,8 +986,7 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { dst_dir.append(adb_basename(src_path)); dst_dir.append(adb_basename(src_path)); } } success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), false, false); false, false); continue; continue; } else if (!should_push_file(st.st_mode)) { } else if (!should_push_file(st.st_mode)) { sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode); sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode); Loading Loading @@ -899,17 +1015,6 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { return success; 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, static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list, const std::string& rpath, const std::string& lpath) { const std::string& rpath, const std::string& lpath) { std::vector<copyinfo> dirlist; std::vector<copyinfo> dirlist; Loading Loading @@ -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. // Check each symlink we found to see whether it's a file or directory. for (copyinfo& link_ci : linklist) { 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)); dirlist.emplace_back(std::move(link_ci)); } else { } else { file_list->emplace_back(std::move(link_ci)); file_list->emplace_back(std::move(link_ci)); Loading Loading @@ -1073,22 +1184,19 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, for (const char* src_path : srcs) { for (const char* src_path : srcs) { const char* dst_path = dst; const char* dst_path = dst; unsigned src_mode, src_time, src_size; struct stat src_st; if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) { if (!sync_stat_fallback(sc, src_path, &src_st)) { sc.Error("failed to stat remote object '%s'", src_path); if (errno == ENOPROTOOPT) { return false; } if (src_mode == 0) { sc.Error("remote object '%s' does not exist", src_path); sc.Error("remote object '%s' does not exist", src_path); success = false; } else { continue; sc.Error("failed to stat remote object '%s': %s", src_path, strerror(errno)); } } bool src_isdir = S_ISDIR(src_mode); success = false; if (S_ISLNK(src_mode)) { continue; src_isdir = remote_symlink_isdir(sc, src_path); } } bool src_isdir = S_ISDIR(src_st.st_mode); if (src_isdir) { if (src_isdir) { std::string dst_dir = dst; std::string dst_dir = dst; Loading @@ -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); success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs); continue; continue; } else if (!should_pull_file(src_mode)) { } else if (!should_pull_file(src_st.st_mode)) { sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_mode); sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode); continue; continue; } } Loading @@ -1123,13 +1231,13 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, } } sc.NewTransfer(); sc.NewTransfer(); sc.SetExpectedTotalBytes(src_size); sc.SetExpectedTotalBytes(src_st.st_size); if (!sync_recv(sc, src_path, dst_path, name)) { if (!sync_recv(sc, src_path, dst_path, name)) { success = false; success = false; continue; 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; success = false; continue; continue; } } Loading adb/file_sync_service.cpp +61 −27 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include "adb_io.h" #include "adb_io.h" #include "adb_utils.h" #include "adb_utils.h" #include "security_log_tags.h" #include "security_log_tags.h" #include "sysdeps/errno.h" static bool should_use_fs_config(const std::string& path) { static bool should_use_fs_config(const std::string& path) { // TODO: use fs_config to configure permissions on /data. // TODO: use fs_config to configure permissions on /data. Loading Loading @@ -98,18 +99,47 @@ static bool secure_mkdirs(const std::string& path) { return true; return true; } } static bool do_stat(int s, const char* path) { static bool do_lstat_v1(int s, const char* path) { syncmsg msg; syncmsg msg = {}; msg.stat.id = ID_STAT; msg.stat_v1.id = ID_LSTAT_V1; struct stat st = {}; struct stat st = {}; // TODO: add a way to report that the stat failed! lstat(path, &st); lstat(path, &st); msg.stat.mode = st.st_mode; msg.stat_v1.mode = st.st_mode; msg.stat.size = st.st_size; msg.stat_v1.size = st.st_size; msg.stat.time = st.st_mtime; 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; return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)); 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_v2, sizeof(msg.stat_v2)); } } static bool do_list(int s, const char* path) { static bool do_list(int s, const char* path) { Loading Loading @@ -427,8 +457,12 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) { D("sync: '%.4s' '%s'", id, name); D("sync: '%.4s' '%s'", id, name); switch (request.id) { switch (request.id) { case ID_STAT: case ID_LSTAT_V1: if (!do_stat(fd, name)) return false; 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; break; case ID_LIST: case ID_LIST: if (!do_list(fd, name)) return false; if (!do_list(fd, name)) return false; Loading @@ -442,15 +476,15 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) { case ID_QUIT: case ID_QUIT: return false; return false; default: default: SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", SendSyncFail( id, request.id)); fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", id, request.id)); return false; return false; } } return true; return true; } } void file_sync_service(int fd, void* cookie) { void file_sync_service(int fd, void*) { std::vector<char> buffer(SYNC_DATA_MAX); std::vector<char> buffer(SYNC_DATA_MAX); while (handle_sync_command(fd, buffer)) { while (handle_sync_command(fd, buffer)) { Loading adb/file_sync_service.h +18 −2 Original line number Original line Diff line number Diff line Loading @@ -22,7 +22,9 @@ #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) #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_LIST MKID('L','I','S','T') #define ID_SEND MKID('S','E','N','D') #define ID_SEND MKID('S','E','N','D') #define ID_RECV MKID('R','E','C','V') #define ID_RECV MKID('R','E','C','V') Loading @@ -45,7 +47,21 @@ union syncmsg { uint32_t mode; uint32_t mode; uint32_t size; uint32_t size; uint32_t time; 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)) { struct __attribute__((packed)) { uint32_t id; uint32_t id; uint32_t mode; uint32_t mode; Loading Loading
adb/Android.mk +1 −0 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ LIBADB_SRC_FILES := \ fdevent.cpp \ fdevent.cpp \ sockets.cpp \ sockets.cpp \ socket_spec.cpp \ socket_spec.cpp \ sysdeps/errno.cpp \ transport.cpp \ transport.cpp \ transport_local.cpp \ transport_local.cpp \ transport_usb.cpp \ transport_usb.cpp \ Loading
adb/adb.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -51,7 +51,7 @@ constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2; std::string adb_version(); std::string adb_version(); // Increment this when we want to force users to start a new adb server. // 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; class atransport; struct usb_handle; struct usb_handle; Loading
adb/file_sync_client.cpp +173 −65 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include "adb_utils.h" #include "adb_utils.h" #include "file_sync_service.h" #include "file_sync_service.h" #include "line_printer.h" #include "line_printer.h" #include "sysdeps/errno.h" #include "sysdeps/stat.h" #include "sysdeps/stat.h" #include <android-base/file.h> #include <android-base/file.h> Loading Loading @@ -73,8 +74,8 @@ static bool should_push_file(mode_t mode) { struct copyinfo { struct copyinfo { std::string lpath; std::string lpath; std::string rpath; std::string rpath; unsigned int time = 0; int64_t time = 0; unsigned int mode; uint32_t mode; uint64_t size = 0; uint64_t size = 0; bool skip = false; bool skip = false; Loading Loading @@ -201,11 +202,18 @@ class SyncConnection { max = SYNC_DATA_MAX; // TODO: decide at runtime. max = SYNC_DATA_MAX; // TODO: decide at runtime. std::string error; 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); fd = adb_connect("sync:", &error); if (fd < 0) { if (fd < 0) { Error("connect failed: %s", error.c_str()); Error("connect failed: %s", error.c_str()); } } } } } ~SyncConnection() { ~SyncConnection() { if (!IsValid()) return; if (!IsValid()) return; Loading Loading @@ -290,6 +298,77 @@ class SyncConnection { return WriteFdExactly(fd, &buf[0], buf.size()); 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 // Sending header, payload, and footer in a single write makes a huge // difference to "adb sync" performance. // difference to "adb sync" performance. bool SendSmallFile(const char* path_and_mode, bool SendSmallFile(const char* path_and_mode, Loading Loading @@ -427,7 +506,7 @@ class SyncConnection { return false; return false; } } buf[msg.status.msglen] = 0; 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; return false; } } Loading Loading @@ -498,6 +577,7 @@ class SyncConnection { private: private: bool expect_done_; bool expect_done_; bool have_stat_v2_; TransferLedger global_ledger_; TransferLedger global_ledger_; TransferLedger current_ledger_; TransferLedger current_ledger_; Loading Loading @@ -553,23 +633,45 @@ static bool sync_ls(SyncConnection& sc, const char* path, } } } } static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp, static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) { unsigned int* mode, unsigned int* size) { return sc.SendStat(path) && sc.FinishStat(st); syncmsg msg; if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) { return false; } } if (timestamp) *timestamp = msg.stat.time; static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) { if (mode) *mode = msg.stat.mode; return sc.SendLstat(path) && sc.FinishStat(st); if (size) *size = msg.stat.size; } static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) { if (sync_stat(sc, path, st)) { return true; return true; } } static bool sync_stat(SyncConnection& sc, const char* path, if (errno != ENOTSUP) { unsigned int* timestamp, unsigned int* mode, unsigned int* size) { return false; return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, 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_send(SyncConnection& sc, const char* lpath, const char* rpath, static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, Loading Loading @@ -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, static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, const char* name=nullptr) { const char* name=nullptr) { unsigned size = 0; struct stat st; if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false; 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; if (!sc.SendRequest(ID_RECV, rpath)) return false; Loading Loading @@ -673,7 +778,7 @@ static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bytes_copied += msg.data.size; bytes_copied += msg.data.size; sc.RecordBytesTransferred(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); sc.RecordFilesTransferred(1); Loading Loading @@ -776,24 +881,24 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, if (check_timestamps) { if (check_timestamps) { for (const copyinfo& ci : file_list) { 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; return false; } } } } for (copyinfo& ci : file_list) { for (copyinfo& ci : file_list) { unsigned int timestamp, mode, size; struct stat st; if (!sync_finish_stat(sc, ×tamp, &mode, &size)) { if (sc.FinishStat(&st)) { return false; if (st.st_size == static_cast<off_t>(ci.size)) { } if (size == ci.size) { // For links, we cannot update the atime/mtime. // For links, we cannot update the atime/mtime. if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) || if ((S_ISREG(ci.mode & st.st_mode) && st.st_mtime == ci.time) || (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) { (S_ISLNK(ci.mode & st.st_mode) && st.st_mtime >= ci.time)) { ci.skip = true; ci.skip = true; } } } } } } } } } sc.ComputeExpectedTotalBytes(file_list); sc.ComputeExpectedTotalBytes(file_list); Loading Loading @@ -821,10 +926,22 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { if (!sc.IsValid()) return false; if (!sc.IsValid()) return false; bool success = true; bool success = true; unsigned dst_mode; bool dst_exists; if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false; bool dst_isdir; bool dst_exists = (dst_mode != 0); bool dst_isdir = S_ISDIR(dst_mode); 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 (!dst_isdir) { if (srcs.size() > 1) { if (srcs.size() > 1) { Loading Loading @@ -869,8 +986,7 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { dst_dir.append(adb_basename(src_path)); dst_dir.append(adb_basename(src_path)); } } success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), false, false); false, false); continue; continue; } else if (!should_push_file(st.st_mode)) { } else if (!should_push_file(st.st_mode)) { sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode); sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode); Loading Loading @@ -899,17 +1015,6 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { return success; 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, static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list, const std::string& rpath, const std::string& lpath) { const std::string& rpath, const std::string& lpath) { std::vector<copyinfo> dirlist; std::vector<copyinfo> dirlist; Loading Loading @@ -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. // Check each symlink we found to see whether it's a file or directory. for (copyinfo& link_ci : linklist) { 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)); dirlist.emplace_back(std::move(link_ci)); } else { } else { file_list->emplace_back(std::move(link_ci)); file_list->emplace_back(std::move(link_ci)); Loading Loading @@ -1073,22 +1184,19 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, for (const char* src_path : srcs) { for (const char* src_path : srcs) { const char* dst_path = dst; const char* dst_path = dst; unsigned src_mode, src_time, src_size; struct stat src_st; if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) { if (!sync_stat_fallback(sc, src_path, &src_st)) { sc.Error("failed to stat remote object '%s'", src_path); if (errno == ENOPROTOOPT) { return false; } if (src_mode == 0) { sc.Error("remote object '%s' does not exist", src_path); sc.Error("remote object '%s' does not exist", src_path); success = false; } else { continue; sc.Error("failed to stat remote object '%s': %s", src_path, strerror(errno)); } } bool src_isdir = S_ISDIR(src_mode); success = false; if (S_ISLNK(src_mode)) { continue; src_isdir = remote_symlink_isdir(sc, src_path); } } bool src_isdir = S_ISDIR(src_st.st_mode); if (src_isdir) { if (src_isdir) { std::string dst_dir = dst; std::string dst_dir = dst; Loading @@ -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); success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs); continue; continue; } else if (!should_pull_file(src_mode)) { } else if (!should_pull_file(src_st.st_mode)) { sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_mode); sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode); continue; continue; } } Loading @@ -1123,13 +1231,13 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, } } sc.NewTransfer(); sc.NewTransfer(); sc.SetExpectedTotalBytes(src_size); sc.SetExpectedTotalBytes(src_st.st_size); if (!sync_recv(sc, src_path, dst_path, name)) { if (!sync_recv(sc, src_path, dst_path, name)) { success = false; success = false; continue; 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; success = false; continue; continue; } } Loading
adb/file_sync_service.cpp +61 −27 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include "adb_io.h" #include "adb_io.h" #include "adb_utils.h" #include "adb_utils.h" #include "security_log_tags.h" #include "security_log_tags.h" #include "sysdeps/errno.h" static bool should_use_fs_config(const std::string& path) { static bool should_use_fs_config(const std::string& path) { // TODO: use fs_config to configure permissions on /data. // TODO: use fs_config to configure permissions on /data. Loading Loading @@ -98,18 +99,47 @@ static bool secure_mkdirs(const std::string& path) { return true; return true; } } static bool do_stat(int s, const char* path) { static bool do_lstat_v1(int s, const char* path) { syncmsg msg; syncmsg msg = {}; msg.stat.id = ID_STAT; msg.stat_v1.id = ID_LSTAT_V1; struct stat st = {}; struct stat st = {}; // TODO: add a way to report that the stat failed! lstat(path, &st); lstat(path, &st); msg.stat.mode = st.st_mode; msg.stat_v1.mode = st.st_mode; msg.stat.size = st.st_size; msg.stat_v1.size = st.st_size; msg.stat.time = st.st_mtime; 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; return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)); 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_v2, sizeof(msg.stat_v2)); } } static bool do_list(int s, const char* path) { static bool do_list(int s, const char* path) { Loading Loading @@ -427,8 +457,12 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) { D("sync: '%.4s' '%s'", id, name); D("sync: '%.4s' '%s'", id, name); switch (request.id) { switch (request.id) { case ID_STAT: case ID_LSTAT_V1: if (!do_stat(fd, name)) return false; 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; break; case ID_LIST: case ID_LIST: if (!do_list(fd, name)) return false; if (!do_list(fd, name)) return false; Loading @@ -442,15 +476,15 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) { case ID_QUIT: case ID_QUIT: return false; return false; default: default: SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", SendSyncFail( id, request.id)); fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", id, request.id)); return false; return false; } } return true; return true; } } void file_sync_service(int fd, void* cookie) { void file_sync_service(int fd, void*) { std::vector<char> buffer(SYNC_DATA_MAX); std::vector<char> buffer(SYNC_DATA_MAX); while (handle_sync_command(fd, buffer)) { while (handle_sync_command(fd, buffer)) { Loading
adb/file_sync_service.h +18 −2 Original line number Original line Diff line number Diff line Loading @@ -22,7 +22,9 @@ #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) #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_LIST MKID('L','I','S','T') #define ID_SEND MKID('S','E','N','D') #define ID_SEND MKID('S','E','N','D') #define ID_RECV MKID('R','E','C','V') #define ID_RECV MKID('R','E','C','V') Loading @@ -45,7 +47,21 @@ union syncmsg { uint32_t mode; uint32_t mode; uint32_t size; uint32_t size; uint32_t time; 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)) { struct __attribute__((packed)) { uint32_t id; uint32_t id; uint32_t mode; uint32_t mode; Loading