Merge changes I6ff85723,Ia7d743d5
am: f4ddee0f32
Change-Id: If80e3c463f93ac6eb6785664bc019b3c68b0c648
This commit is contained in:
commit
c01a10f1b6
|
@ -52,6 +52,8 @@
|
|||
#include <android-base/strings.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
typedef void(sync_ls_cb)(unsigned mode, uint64_t size, uint64_t time, const char* name);
|
||||
|
||||
struct syncsendbuf {
|
||||
unsigned id;
|
||||
unsigned size;
|
||||
|
@ -210,6 +212,7 @@ class SyncConnection {
|
|||
Error("failed to get feature set: %s", error.c_str());
|
||||
} else {
|
||||
have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
|
||||
have_ls_v2_ = CanUseFeature(features_, kFeatureLs2);
|
||||
fd.reset(adb_connect("sync:", &error));
|
||||
if (fd < 0) {
|
||||
Error("connect failed: %s", error.c_str());
|
||||
|
@ -357,7 +360,7 @@ class SyncConnection {
|
|||
<< msg.stat_v1.id;
|
||||
}
|
||||
|
||||
if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) {
|
||||
if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.mtime == 0) {
|
||||
// There's no way for us to know what the error was.
|
||||
errno = ENOPROTOOPT;
|
||||
return false;
|
||||
|
@ -365,13 +368,52 @@ class SyncConnection {
|
|||
|
||||
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;
|
||||
st->st_ctime = msg.stat_v1.mtime;
|
||||
st->st_mtime = msg.stat_v1.mtime;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SendLs(const char* path) {
|
||||
return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path);
|
||||
}
|
||||
|
||||
private:
|
||||
template <bool v2>
|
||||
static bool FinishLsImpl(borrowed_fd fd, const std::function<sync_ls_cb>& callback) {
|
||||
using dent_type =
|
||||
std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>;
|
||||
|
||||
while (true) {
|
||||
dent_type dent;
|
||||
if (!ReadFdExactly(fd, &dent, sizeof(dent))) return false;
|
||||
|
||||
uint32_t expected_id = v2 ? ID_DENT_V2 : ID_DENT_V1;
|
||||
if (dent.id == ID_DONE) return true;
|
||||
if (dent.id != expected_id) return false;
|
||||
|
||||
// Maximum length of a file name excluding null terminator (NAME_MAX) on Linux is 255.
|
||||
char buf[256];
|
||||
size_t len = dent.namelen;
|
||||
if (len > 255) return false;
|
||||
|
||||
if (!ReadFdExactly(fd, buf, len)) return false;
|
||||
buf[len] = 0;
|
||||
|
||||
callback(dent.mode, dent.size, dent.mtime, buf);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool FinishLs(const std::function<sync_ls_cb>& callback) {
|
||||
if (have_ls_v2_) {
|
||||
return FinishLsImpl<true>(this->fd, callback);
|
||||
} else {
|
||||
return FinishLsImpl<false>(this->fd, callback);
|
||||
}
|
||||
}
|
||||
|
||||
// Sending header, payload, and footer in a single write makes a huge
|
||||
// difference to "adb sync" performance.
|
||||
bool SendSmallFile(const char* path_and_mode,
|
||||
|
@ -578,6 +620,7 @@ class SyncConnection {
|
|||
bool expect_done_;
|
||||
FeatureSet features_;
|
||||
bool have_stat_v2_;
|
||||
bool have_ls_v2_;
|
||||
|
||||
TransferLedger global_ledger_;
|
||||
TransferLedger current_ledger_;
|
||||
|
@ -609,28 +652,9 @@ class SyncConnection {
|
|||
}
|
||||
};
|
||||
|
||||
typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
|
||||
|
||||
static bool sync_ls(SyncConnection& sc, const char* path,
|
||||
const std::function<sync_ls_cb>& func) {
|
||||
if (!sc.SendRequest(ID_LIST, path)) return false;
|
||||
|
||||
while (true) {
|
||||
syncmsg msg;
|
||||
if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
|
||||
|
||||
if (msg.dent.id == ID_DONE) return true;
|
||||
if (msg.dent.id != ID_DENT) return false;
|
||||
|
||||
size_t len = msg.dent.namelen;
|
||||
if (len > 256) return false; // TODO: resize buffer? continue?
|
||||
|
||||
char buf[257];
|
||||
if (!ReadFdExactly(sc.fd, buf, len)) return false;
|
||||
buf[len] = 0;
|
||||
|
||||
func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
|
||||
}
|
||||
return sc.SendLs(path) && sc.FinishLs(func);
|
||||
}
|
||||
|
||||
static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
|
||||
|
@ -787,9 +811,8 @@ bool do_sync_ls(const char* path) {
|
|||
SyncConnection sc;
|
||||
if (!sc.IsValid()) return false;
|
||||
|
||||
return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
|
||||
const char* name) {
|
||||
printf("%08x %08x %08x %s\n", mode, size, time, name);
|
||||
return sync_ls(sc, path, [](unsigned mode, uint64_t size, uint64_t time, const char* name) {
|
||||
printf("%08x %08" PRIx64 " %08" PRIx64 " %s\n", mode, size, time, name);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1062,7 +1085,7 @@ static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_li
|
|||
file_list->push_back(ci);
|
||||
|
||||
// Put the files/dirs in rpath on the lists.
|
||||
auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
|
||||
auto callback = [&](unsigned mode, uint64_t size, uint64_t time, const char* name) {
|
||||
if (IsDotOrDotDot(name)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ static bool do_lstat_v1(int s, const char* path) {
|
|||
lstat(path, &st);
|
||||
msg.stat_v1.mode = st.st_mode;
|
||||
msg.stat_v1.size = st.st_size;
|
||||
msg.stat_v1.time = st.st_mtime;
|
||||
msg.stat_v1.mtime = st.st_mtime;
|
||||
return WriteFdExactly(s, &msg.stat_v1, sizeof(msg.stat_v1));
|
||||
}
|
||||
|
||||
|
@ -174,40 +174,73 @@ static bool do_stat_v2(int s, uint32_t id, const char* path) {
|
|||
return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2));
|
||||
}
|
||||
|
||||
template <bool v2>
|
||||
static bool do_list(int s, const char* path) {
|
||||
dirent* de;
|
||||
|
||||
syncmsg msg;
|
||||
msg.dent.id = ID_DENT;
|
||||
using MessageType =
|
||||
std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>;
|
||||
MessageType msg;
|
||||
uint32_t msg_id;
|
||||
if constexpr (v2) {
|
||||
msg_id = ID_DENT_V2;
|
||||
} else {
|
||||
msg_id = ID_DENT_V1;
|
||||
}
|
||||
|
||||
std::unique_ptr<DIR, int(*)(DIR*)> d(opendir(path), closedir);
|
||||
if (!d) goto done;
|
||||
|
||||
while ((de = readdir(d.get()))) {
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.id = msg_id;
|
||||
|
||||
std::string filename(StringPrintf("%s/%s", path, de->d_name));
|
||||
|
||||
struct stat st;
|
||||
if (lstat(filename.c_str(), &st) == 0) {
|
||||
size_t d_name_length = strlen(de->d_name);
|
||||
msg.dent.mode = st.st_mode;
|
||||
msg.dent.size = st.st_size;
|
||||
msg.dent.time = st.st_mtime;
|
||||
msg.dent.namelen = d_name_length;
|
||||
msg.mode = st.st_mode;
|
||||
msg.size = st.st_size;
|
||||
msg.mtime = st.st_mtime;
|
||||
|
||||
if (!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
|
||||
!WriteFdExactly(s, de->d_name, d_name_length)) {
|
||||
return false;
|
||||
if constexpr (v2) {
|
||||
msg.dev = st.st_dev;
|
||||
msg.ino = st.st_ino;
|
||||
msg.nlink = st.st_nlink;
|
||||
msg.uid = st.st_uid;
|
||||
msg.gid = st.st_gid;
|
||||
msg.atime = st.st_atime;
|
||||
msg.ctime = st.st_ctime;
|
||||
}
|
||||
} else {
|
||||
if constexpr (v2) {
|
||||
msg.error = errno;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
size_t d_name_length = strlen(de->d_name);
|
||||
msg.namelen = d_name_length;
|
||||
|
||||
if (!WriteFdExactly(s, &msg, sizeof(msg)) ||
|
||||
!WriteFdExactly(s, de->d_name, d_name_length)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
msg.dent.id = ID_DONE;
|
||||
msg.dent.mode = 0;
|
||||
msg.dent.size = 0;
|
||||
msg.dent.time = 0;
|
||||
msg.dent.namelen = 0;
|
||||
return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.id = ID_DONE;
|
||||
return WriteFdExactly(s, &msg, sizeof(msg));
|
||||
}
|
||||
|
||||
static bool do_list_v1(int s, const char* path) {
|
||||
return do_list<false>(s, path);
|
||||
}
|
||||
|
||||
static bool do_list_v2(int s, const char* path) {
|
||||
return do_list<true>(s, path);
|
||||
}
|
||||
|
||||
// Make sure that SendFail from adb_io.cpp isn't accidentally used in this file.
|
||||
|
@ -499,8 +532,10 @@ static const char* sync_id_to_name(uint32_t id) {
|
|||
return "lstat_v2";
|
||||
case ID_STAT_V2:
|
||||
return "stat_v2";
|
||||
case ID_LIST:
|
||||
return "list";
|
||||
case ID_LIST_V1:
|
||||
return "list_v1";
|
||||
case ID_LIST_V2:
|
||||
return "list_v2";
|
||||
case ID_SEND:
|
||||
return "send";
|
||||
case ID_RECV:
|
||||
|
@ -546,8 +581,11 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) {
|
|||
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;
|
||||
case ID_LIST_V1:
|
||||
if (!do_list_v1(fd, name)) return false;
|
||||
break;
|
||||
case ID_LIST_V2:
|
||||
if (!do_list_v2(fd, name)) return false;
|
||||
break;
|
||||
case ID_SEND:
|
||||
if (!do_send(fd, name, buffer)) return false;
|
||||
|
|
|
@ -21,10 +21,14 @@
|
|||
#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_V1 MKID('L', 'I', 'S', 'T')
|
||||
#define ID_LIST_V2 MKID('L', 'I', 'S', '2')
|
||||
#define ID_DENT_V1 MKID('D', 'E', 'N', 'T')
|
||||
#define ID_DENT_V2 MKID('D', 'N', 'T', '2')
|
||||
|
||||
#define ID_SEND MKID('S', 'E', 'N', 'D')
|
||||
#define ID_RECV MKID('R', 'E', 'C', 'V')
|
||||
#define ID_DENT MKID('D', 'E', 'N', 'T')
|
||||
#define ID_DONE MKID('D', 'O', 'N', 'E')
|
||||
#define ID_DATA MKID('D', 'A', 'T', 'A')
|
||||
#define ID_OKAY MKID('O', 'K', 'A', 'Y')
|
||||
|
@ -42,7 +46,7 @@ union syncmsg {
|
|||
uint32_t id;
|
||||
uint32_t mode;
|
||||
uint32_t size;
|
||||
uint32_t time;
|
||||
uint32_t mtime;
|
||||
} stat_v1;
|
||||
struct __attribute__((packed)) {
|
||||
uint32_t id;
|
||||
|
@ -62,17 +66,32 @@ union syncmsg {
|
|||
uint32_t id;
|
||||
uint32_t mode;
|
||||
uint32_t size;
|
||||
uint32_t time;
|
||||
uint32_t mtime;
|
||||
uint32_t namelen;
|
||||
} dent;
|
||||
} dent_v1; // followed by `namelen` bytes of the name.
|
||||
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;
|
||||
uint32_t namelen;
|
||||
} dent_v2; // followed by `namelen` bytes of the name.
|
||||
struct __attribute__((packed)) {
|
||||
uint32_t id;
|
||||
uint32_t size;
|
||||
} data;
|
||||
} data; // followed by `size` bytes of data.
|
||||
struct __attribute__((packed)) {
|
||||
uint32_t id;
|
||||
uint32_t msglen;
|
||||
} status;
|
||||
} status; // followed by `msglen` bytes of error message, if id == ID_FAIL.
|
||||
};
|
||||
|
||||
#define SYNC_DATA_MAX (64 * 1024)
|
||||
|
|
|
@ -66,6 +66,7 @@ static auto& transport_lock = *new std::recursive_mutex();
|
|||
const char* const kFeatureShell2 = "shell_v2";
|
||||
const char* const kFeatureCmd = "cmd";
|
||||
const char* const kFeatureStat2 = "stat_v2";
|
||||
const char* const kFeatureLs2 = "ls_v2";
|
||||
const char* const kFeatureLibusb = "libusb";
|
||||
const char* const kFeaturePushSync = "push_sync";
|
||||
const char* const kFeatureApex = "apex";
|
||||
|
@ -1035,6 +1036,7 @@ const FeatureSet& supported_features() {
|
|||
kFeatureShell2,
|
||||
kFeatureCmd,
|
||||
kFeatureStat2,
|
||||
kFeatureLs2,
|
||||
kFeatureFixedPushMkdir,
|
||||
kFeatureApex,
|
||||
kFeatureAbb,
|
||||
|
|
|
@ -57,6 +57,7 @@ extern const char* const kFeatureShell2;
|
|||
// The 'cmd' command is available
|
||||
extern const char* const kFeatureCmd;
|
||||
extern const char* const kFeatureStat2;
|
||||
extern const char* const kFeatureLs2;
|
||||
// The server is running with libusb enabled.
|
||||
extern const char* const kFeatureLibusb;
|
||||
// adbd supports `push --sync`.
|
||||
|
|
Loading…
Reference in New Issue