diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp index b8827ef39..7e470e1fc 100644 --- a/adb/client/file_sync_client.cpp +++ b/adb/client/file_sync_client.cpp @@ -681,9 +681,7 @@ static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, if (sync) { struct stat st; if (sync_lstat(sc, rpath, &st)) { - // For links, we cannot update the atime/mtime. - if ((S_ISREG(mode & st.st_mode) && st.st_mtime == static_cast(mtime)) || - (S_ISLNK(mode & st.st_mode) && st.st_mtime >= static_cast(mtime))) { + if (st.st_mtime == static_cast(mtime)) { sc.RecordFilesSkipped(1); return true; } @@ -921,12 +919,8 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, for (copyinfo& ci : file_list) { struct stat st; if (sc.FinishStat(&st)) { - if (st.st_size == static_cast(ci.size)) { - // For links, we cannot update the atime/mtime. - if ((S_ISREG(ci.mode & st.st_mode) && st.st_mtime == ci.time) || - (S_ISLNK(ci.mode & st.st_mode) && st.st_mtime >= ci.time)) { - ci.skip = true; - } + if (st.st_size == static_cast(ci.size) && st.st_mtime == ci.time) { + ci.skip = true; } } } diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp index 9e1760db9..70deb31fd 100644 --- a/adb/daemon/file_sync_service.cpp +++ b/adb/daemon/file_sync_service.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -242,10 +243,10 @@ static bool SendSyncFailErrno(int fd, const std::string& reason) { return SendSyncFail(fd, StringPrintf("%s: %s", reason.c_str(), strerror(errno))); } -static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint64_t capabilities, - mode_t mode, std::vector& buffer, bool do_unlink) { +static bool handle_send_file(int s, const char* path, uint32_t* timestamp, uid_t uid, gid_t gid, + uint64_t capabilities, mode_t mode, std::vector& buffer, + bool do_unlink) { syncmsg msg; - unsigned int timestamp = 0; __android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path); @@ -291,7 +292,7 @@ static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint if (msg.data.id != ID_DATA) { if (msg.data.id == ID_DONE) { - timestamp = msg.data.size; + *timestamp = msg.data.size; break; } SendSyncFail(s, "invalid data message"); @@ -316,11 +317,6 @@ static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint goto fail; } - utimbuf u; - u.actime = timestamp; - u.modtime = timestamp; - utime(path, &u); - msg.status.id = ID_OKAY; msg.status.msglen = 0; return WriteFdExactly(s, &msg.status, sizeof(msg.status)); @@ -360,9 +356,12 @@ abort: } #if defined(_WIN32) -extern bool handle_send_link(int s, const std::string& path, std::vector& buffer) __attribute__((error("no symlinks on Windows"))); +extern bool handle_send_link(int s, const std::string& path, + uint32_t* timestamp, std::vector& buffer) + __attribute__((error("no symlinks on Windows"))); #else -static bool handle_send_link(int s, const std::string& path, std::vector& buffer) { +static bool handle_send_link(int s, const std::string& path, uint32_t* timestamp, + std::vector& buffer) { syncmsg msg; if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; @@ -399,6 +398,7 @@ static bool handle_send_link(int s, const std::string& path, std::vector& if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false; if (msg.data.id == ID_DONE) { + *timestamp = msg.data.size; msg.status.id = ID_OKAY; msg.status.msglen = 0; if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false; @@ -448,24 +448,40 @@ static bool do_send(int s, const std::string& spec, std::vector& buffer) { adb_unlink(path.c_str()); } + bool result; + uint32_t timestamp; if (S_ISLNK(mode)) { - return handle_send_link(s, path.c_str(), buffer); + result = handle_send_link(s, path.c_str(), ×tamp, buffer); + } else { + // Copy user permission bits to "group" and "other" permissions. + mode &= 0777; + mode |= ((mode >> 3) & 0070); + mode |= ((mode >> 3) & 0007); + + uid_t uid = -1; + gid_t gid = -1; + uint64_t capabilities = 0; + if (should_use_fs_config(path)) { + unsigned int broken_api_hack = mode; + fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &capabilities); + mode = broken_api_hack; + } + + result = handle_send_file(s, path.c_str(), ×tamp, uid, gid, capabilities, mode, buffer, + do_unlink); } - // Copy user permission bits to "group" and "other" permissions. - mode &= 0777; - mode |= ((mode >> 3) & 0070); - mode |= ((mode >> 3) & 0007); - - uid_t uid = -1; - gid_t gid = -1; - uint64_t capabilities = 0; - if (should_use_fs_config(path)) { - unsigned int broken_api_hack = mode; - fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &capabilities); - mode = broken_api_hack; + if (!result) { + return false; } - return handle_send_file(s, path.c_str(), uid, gid, capabilities, mode, buffer, do_unlink); + + struct timeval tv[2]; + tv[0].tv_sec = timestamp; + tv[0].tv_usec = 0; + tv[1].tv_sec = timestamp; + tv[1].tv_usec = 0; + lutimes(path.c_str(), tv); + return true; } static bool do_recv(int s, const char* path, std::vector& buffer) { diff --git a/adb/transport.cpp b/adb/transport.cpp index 90f94ee1e..0c7b0b69b 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -71,6 +71,7 @@ const char* const kFeaturePushSync = "push_sync"; const char* const kFeatureApex = "apex"; const char* const kFeatureFixedPushMkdir = "fixed_push_mkdir"; const char* const kFeatureAbb = "abb"; +const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp"; namespace { @@ -1005,8 +1006,13 @@ size_t atransport::get_max_payload() const { const FeatureSet& supported_features() { // Local static allocation to avoid global non-POD variables. static const FeatureSet* features = new FeatureSet{ - kFeatureShell2, kFeatureCmd, kFeatureStat2, - kFeatureFixedPushMkdir, kFeatureApex, kFeatureAbb, + kFeatureShell2, + kFeatureCmd, + kFeatureStat2, + kFeatureFixedPushMkdir, + kFeatureApex, + kFeatureAbb, + kFeatureFixedPushSymlinkTimestamp, // Increment ADB_SERVER_VERSION when adding a feature that adbd needs // to know about. Otherwise, the client can be stuck running an old // version of the server even after upgrading their copy of adb. diff --git a/adb/transport.h b/adb/transport.h index 065c81f2d..a0174b8fc 100644 --- a/adb/transport.h +++ b/adb/transport.h @@ -67,6 +67,8 @@ extern const char* const kFeatureApex; extern const char* const kFeatureFixedPushMkdir; // adbd supports android binder bridge (abb). extern const char* const kFeatureAbb; +// adbd properly updates symlink timestamps on push. +extern const char* const kFeatureFixedPushSymlinkTimestamp; TransportId NextTransportId();