adb sync cleanup.
We can double the speed of "adb sync" (on N9) if we increase SYNC_DATA_MAX
from 64KiB to 256KiB. This change doesn't do that, because I still haven't
managed to plumb through the information about whether we're a new adb/adbd
to file_sync_client.cpp and file_sync_service.cpp. But this is already a big
change with a lot of cleanup, so let's do the cleanup and worry about the
intended change another day...
This change does improve performance somewhat by halving the number of
lstat(2) calls made on the client side, and ensuring that most packets are
sent with a single write. This has the pleasing result of making the null
sync on an AOSP N9 go from just over 300ms to around 100ms, which means it
now seems instantaneous (https://en.wikipedia.org/wiki/Mental_chronometry).
Change-Id: If9f6d4c1f93ec752b95f71211bbbb1c513045166
diff --git a/file_sync_client.cpp b/file_sync_client.cpp
index da80013..c37c6dd 100644
--- a/file_sync_client.cpp
+++ b/file_sync_client.cpp
@@ -35,36 +35,21 @@
#include "adb_utils.h"
#include "file_sync_service.h"
+#include <base/strings.h>
#include <base/stringprintf.h>
-static unsigned long long total_bytes;
-static long long start_time;
+struct syncsendbuf {
+ unsigned id;
+ unsigned size;
+ char data[SYNC_DATA_MAX];
+};
-static long long NOW()
-{
+static syncsendbuf send_buffer;
+
+static long long NOW() {
struct timeval tv;
gettimeofday(&tv, 0);
- return ((long long) tv.tv_usec) +
- 1000000LL * ((long long) tv.tv_sec);
-}
-
-static void BEGIN()
-{
- total_bytes = 0;
- start_time = NOW();
-}
-
-static void END()
-{
- long long t = NOW() - start_time;
- if(total_bytes == 0) return;
-
- if (t == 0) /* prevent division by 0 :-) */
- t = 1000000;
-
- fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
- ((total_bytes * 1000000LL) / t) / 1024LL,
- total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+ return ((long long) tv.tv_usec) + 1000000LL * ((long long) tv.tv_sec);
}
static void print_transfer_progress(uint64_t bytes_current,
@@ -82,148 +67,123 @@
fflush(stderr);
}
-static void sync_quit(int fd) {
- syncmsg msg;
-
- msg.req.id = ID_QUIT;
- msg.req.namelen = 0;
-
- WriteFdExactly(fd, &msg.req, sizeof(msg.req));
-}
-
-typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
-
-static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
- int len = strlen(path);
- if (len > 1024) goto fail;
-
- syncmsg msg;
- msg.req.id = ID_LIST;
- msg.req.namelen = htoll(len);
-
- if (!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || !WriteFdExactly(fd, path, len)) {
- goto fail;
+static bool SendRequest(int fd, int id, const char* path) {
+ size_t path_length = strlen(path);
+ if (path_length > 1024) {
+ fprintf(stderr, "SendRequest failed: path too long: %zu", path_length);
+ return false;
}
- for (;;) {
- if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
- if (msg.dent.id == ID_DONE) return 0;
- if (msg.dent.id != ID_DENT) break;
+ // Sending header and payload in a single write makes a noticeable
+ // difference to "adb sync" performance.
+ char buf[sizeof(SyncRequest) + path_length] __attribute__((aligned(8)));
+ SyncRequest* req = reinterpret_cast<SyncRequest*>(buf);
+ req->id = id;
+ req->path_length = htoll(path_length);
+ char* data = reinterpret_cast<char*>(req + 1);
+ memcpy(data, path, path_length);
- len = ltohl(msg.dent.namelen);
- if (len > 256) break;
+ return WriteFdExactly(fd, buf, sizeof(buf));
+}
+
+class SyncConnection {
+ public:
+ SyncConnection() : total_bytes(0), start_time_(NOW()) {
+ max = SYNC_DATA_MAX; // TODO: decide at runtime.
+
+ std::string error;
+ fd = adb_connect("sync:", &error);
+ if (fd < 0) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ }
+ }
+
+ ~SyncConnection() {
+ if (!IsValid()) return;
+
+ SendQuit();
+ ShowTransferRate();
+ adb_close(fd);
+ }
+
+ bool IsValid() { return fd >= 0; }
+
+ uint64_t total_bytes;
+
+ // TODO: add a char[max] buffer here, to replace syncsendbuf...
+ int fd;
+ size_t max;
+
+ private:
+ uint64_t start_time_;
+
+ void SendQuit() {
+ SendRequest(fd, ID_QUIT, ""); // TODO: add a SendResponse?
+ }
+
+ void ShowTransferRate() {
+ uint64_t t = NOW() - start_time_;
+ if (total_bytes == 0 || t == 0) return;
+
+ fprintf(stderr, "%lld KB/s (%" PRId64 " bytes in %lld.%03llds)\n",
+ ((total_bytes * 1000000LL) / t) / 1024LL,
+ total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+ }
+};
+
+typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
+
+static bool sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
+ if (!SendRequest(fd, ID_LIST, path)) return false;
+
+ while (true) {
+ syncmsg msg;
+ if (!ReadFdExactly(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 = ltohl(msg.dent.namelen);
+ if (len > 256) return false; // TODO: resize buffer? continue?
char buf[257];
- if (!ReadFdExactly(fd, buf, len)) break;
+ if (!ReadFdExactly(fd, buf, len)) return false;
buf[len] = 0;
func(ltohl(msg.dent.mode), ltohl(msg.dent.size), ltohl(msg.dent.time), buf, cookie);
}
-
-fail:
- adb_close(fd);
- return -1;
}
-struct syncsendbuf {
- unsigned id;
- unsigned size;
- char data[SYNC_DATA_MAX];
-};
+static bool sync_start_stat(SyncConnection& sc, const char* path) {
+ return SendRequest(sc.fd, ID_STAT, path);
+}
-static syncsendbuf send_buffer;
-
-static int sync_readtime(int fd, const char* path, unsigned int* timestamp, unsigned int* mode) {
+static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
+ unsigned int* mode, unsigned int* size) {
syncmsg msg;
- int len = strlen(path);
-
- msg.req.id = ID_STAT;
- msg.req.namelen = htoll(len);
-
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, path, len)) {
- return -1;
+ if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
+ return false;
}
- if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
- return -1;
- }
+ if (timestamp) *timestamp = ltohl(msg.stat.time);
+ if (mode) *mode = ltohl(msg.stat.mode);
+ if (size) *size = ltohl(msg.stat.size);
- if(msg.stat.id != ID_STAT) {
- return -1;
- }
-
- *timestamp = ltohl(msg.stat.time);
- *mode = ltohl(msg.stat.mode);
- return 0;
+ return true;
}
-static int sync_start_readtime(int fd, const char *path)
-{
- syncmsg msg;
- int len = strlen(path);
-
- msg.req.id = ID_STAT;
- msg.req.namelen = htoll(len);
-
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, path, len)) {
- return -1;
- }
-
- return 0;
+static bool sync_stat(SyncConnection& sc, const char* path,
+ unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
+ return sync_start_stat(sc, path) && sync_finish_stat(sc, timestamp, mode, size);
}
-static int sync_finish_readtime(int fd, unsigned int *timestamp,
- unsigned int *mode, unsigned int *size)
-{
- syncmsg msg;
-
- if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
- return -1;
-
- if(msg.stat.id != ID_STAT)
- return -1;
-
- *timestamp = ltohl(msg.stat.time);
- *mode = ltohl(msg.stat.mode);
- *size = ltohl(msg.stat.size);
-
- return 0;
-}
-
-static int sync_readmode(int fd, const char* path, unsigned* mode) {
- syncmsg msg;
- int len = strlen(path);
-
- msg.req.id = ID_STAT;
- msg.req.namelen = htoll(len);
-
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, path, len)) {
- return -1;
- }
-
- if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
- return -1;
- }
-
- if(msg.stat.id != ID_STAT) {
- return -1;
- }
-
- *mode = ltohl(msg.stat.mode);
- return 0;
-}
-
-static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, bool show_progress)
-{
- int lfd, err = 0;
+static int write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
+ int err = 0;
unsigned long long size = 0;
- lfd = adb_open(path, O_RDONLY);
- if(lfd < 0) {
- fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
+ int lfd = adb_open(path, O_RDONLY);
+ if (lfd < 0) {
+ fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
return -1;
}
@@ -231,7 +191,7 @@
// Determine local file size.
struct stat st;
if (stat(path, &st)) {
- fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
+ fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
return -1;
}
@@ -239,29 +199,27 @@
}
sbuf->id = ID_DATA;
- for(;;) {
- int ret;
-
- ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
- if(!ret)
+ while (true) {
+ int ret = adb_read(lfd, sbuf->data, sc.max);
+ if (!ret)
break;
- if(ret < 0) {
+ if (ret < 0) {
if(errno == EINTR)
continue;
- fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
+ fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
break;
}
sbuf->size = htoll(ret);
- if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
+ if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
err = -1;
break;
}
- total_bytes += ret;
+ sc.total_bytes += ret;
if (show_progress) {
- print_transfer_progress(total_bytes, size);
+ print_transfer_progress(sc.total_bytes, size);
}
}
@@ -269,42 +227,11 @@
return err;
}
-static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
- bool show_progress)
-{
- int err = 0;
- int total = 0;
-
- sbuf->id = ID_DATA;
- while (total < size) {
- int count = size - total;
- if (count > SYNC_DATA_MAX) {
- count = SYNC_DATA_MAX;
- }
-
- memcpy(sbuf->data, &file_buffer[total], count);
- sbuf->size = htoll(count);
- if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
- err = -1;
- break;
- }
- total += count;
- total_bytes += count;
-
- if (show_progress) {
- print_transfer_progress(total, size);
- }
- }
-
- return err;
-}
-
#if defined(_WIN32)
-extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
+extern int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
#else
-static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
-{
- int len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
+static int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
+ ssize_t len = readlink(path, sbuf->data, sc.max - 1);
if (len < 0) {
fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
return -1;
@@ -314,131 +241,84 @@
sbuf->size = htoll(len + 1);
sbuf->id = ID_DATA;
- if (!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
+ if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
return -1;
}
- total_bytes += len + 1;
+ sc.total_bytes += len + 1;
return 0;
}
#endif
-static int sync_send(int fd, const char *lpath, const char *rpath,
- unsigned mtime, mode_t mode, bool show_progress)
+static bool sync_send(SyncConnection& sc, const char *lpath, const char *rpath,
+ unsigned mtime, mode_t mode, bool show_progress)
{
- syncmsg msg;
- int len, r;
- syncsendbuf *sbuf = &send_buffer;
- char* file_buffer = NULL;
- int size = 0;
- char tmp[64];
+ syncsendbuf* sbuf = &send_buffer;
- len = strlen(rpath);
- if(len > 1024) goto fail;
+ std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
+ if (!SendRequest(sc.fd, ID_SEND, path_and_mode.c_str())) goto fail;
- snprintf(tmp, sizeof(tmp), ",%d", mode);
- r = strlen(tmp);
-
- msg.req.id = ID_SEND;
- msg.req.namelen = htoll(len + r);
-
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
- free(file_buffer);
+ if (S_ISREG(mode)) {
+ write_data_file(sc, lpath, sbuf, show_progress);
+ } else if (S_ISLNK(mode)) {
+ write_data_link(sc, lpath, sbuf);
+ } else {
goto fail;
}
- if (file_buffer) {
- write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
- free(file_buffer);
- } else if (S_ISREG(mode))
- write_data_file(fd, lpath, sbuf, show_progress);
- else if (S_ISLNK(mode))
- write_data_link(fd, lpath, sbuf);
- else
- goto fail;
-
+ syncmsg msg;
msg.data.id = ID_DONE;
msg.data.size = htoll(mtime);
- if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
- goto fail;
+ if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) goto fail;
- if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
- return -1;
+ if (!ReadFdExactly(sc.fd, &msg.status, sizeof(msg.status))) goto fail;
- if(msg.status.id != ID_OKAY) {
- if(msg.status.id == ID_FAIL) {
- len = ltohl(msg.status.msglen);
- if(len > 256) len = 256;
- if(!ReadFdExactly(fd, sbuf->data, len)) {
- return -1;
- }
+ if (msg.status.id != ID_OKAY) {
+ if (msg.status.id == ID_FAIL) {
+ size_t len = ltohl(msg.status.msglen);
+ if (len > 256) len = 256;
+ if (!ReadFdExactly(sc.fd, sbuf->data, len)) goto fail;
sbuf->data[len] = 0;
- } else
+ } else {
strcpy(sbuf->data, "unknown reason");
-
- fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
- return -1;
+ }
+ fprintf(stderr, "failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
+ return false;
}
- return 0;
+ return true;
fail:
- fprintf(stderr,"protocol failure\n");
- adb_close(fd);
- return -1;
+ fprintf(stderr, "protocol failure\n");
+ return false;
}
-static int sync_recv(int fd, const char* rpath, const char* lpath, bool show_progress) {
+static int sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bool show_progress) {
syncmsg msg;
- int len;
int lfd = -1;
char *buffer = send_buffer.data;
unsigned id;
- unsigned long long size = 0;
- len = strlen(rpath);
- if(len > 1024) return -1;
+ size_t len = strlen(rpath);
+ if (len > 1024) return -1;
+ unsigned size = 0;
if (show_progress) {
- // Determine remote file size.
- syncmsg stat_msg;
- stat_msg.req.id = ID_STAT;
- stat_msg.req.namelen = htoll(len);
-
- if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
- !WriteFdExactly(fd, rpath, len)) {
- return -1;
- }
-
- if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
- return -1;
- }
-
- if (stat_msg.stat.id != ID_STAT) return -1;
-
- size = ltohl(stat_msg.stat.size);
+ if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return -1;
}
- msg.req.id = ID_RECV;
- msg.req.namelen = htoll(len);
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, rpath, len)) {
- return -1;
- }
+ if (!SendRequest(sc.fd, ID_RECV, rpath)) return -1;
+ if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) return -1;
- if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
- return -1;
- }
id = msg.data.id;
- if((id == ID_DATA) || (id == ID_DONE)) {
+ if (id == ID_DATA || id == ID_DONE) {
adb_unlink(lpath);
mkdirs(lpath);
lfd = adb_creat(lpath, 0644);
if(lfd < 0) {
- fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
+ fprintf(stderr, "cannot create '%s': %s\n", lpath, strerror(errno));
return -1;
}
goto handle_data;
@@ -446,37 +326,37 @@
goto remote_error;
}
- for(;;) {
- if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
+ while (true) {
+ if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
return -1;
}
id = msg.data.id;
handle_data:
len = ltohl(msg.data.size);
- if(id == ID_DONE) break;
- if(id != ID_DATA) goto remote_error;
- if(len > SYNC_DATA_MAX) {
- fprintf(stderr,"data overrun\n");
+ if (id == ID_DONE) break;
+ if (id != ID_DATA) goto remote_error;
+ if (len > sc.max) {
+ fprintf(stderr, "msg.data.size too large: %zu (max %zu)\n", len, sc.max);
adb_close(lfd);
return -1;
}
- if(!ReadFdExactly(fd, buffer, len)) {
+ if(!ReadFdExactly(sc.fd, buffer, len)) {
adb_close(lfd);
return -1;
}
if(!WriteFdExactly(lfd, buffer, len)) {
- fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
+ fprintf(stderr, "cannot write '%s': %s\n", rpath, strerror(errno));
adb_close(lfd);
return -1;
}
- total_bytes += len;
+ sc.total_bytes += len;
if (show_progress) {
- print_transfer_progress(total_bytes, size);
+ print_transfer_progress(sc.total_bytes, size);
}
}
@@ -490,7 +370,7 @@
if(id == ID_FAIL) {
len = ltohl(msg.data.size);
if(len > 256) len = 256;
- if(!ReadFdExactly(fd, buffer, len)) {
+ if(!ReadFdExactly(sc.fd, buffer, len)) {
return -1;
}
buffer[len] = 0;
@@ -498,31 +378,20 @@
memcpy(buffer, &id, 4);
buffer[4] = 0;
}
- fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
+ fprintf(stderr, "failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
return 0;
}
-/* --- */
static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
- const char *name, void *cookie)
-{
+ const char* name, void* /*cookie*/) {
printf("%08x %08x %08x %s\n", mode, size, time, name);
}
-int do_sync_ls(const char* path) {
- std::string error;
- int fd = adb_connect("sync:", &error);
- if (fd < 0) {
- fprintf(stderr,"error: %s\n", error.c_str());
- return 1;
- }
+bool do_sync_ls(const char* path) {
+ SyncConnection sc;
+ if (!sc.IsValid()) return false;
- if (sync_ls(fd, path, do_sync_ls_cb, 0)) {
- return 1;
- }
-
- sync_quit(fd);
- return 0;
+ return sync_ls(sc.fd, path, do_sync_ls_cb, 0);
}
struct copyinfo
@@ -545,7 +414,7 @@
copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
if(ci == 0) {
- fprintf(stderr,"out of memory\n");
+ fprintf(stderr, "out of memory\n");
abort();
}
@@ -562,54 +431,41 @@
return ci;
}
+static bool IsDotOrDotDot(const char* name) {
+ return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
+}
-static int local_build_list(copyinfo **filelist,
- const char *lpath, const char *rpath)
-{
- DIR *d;
- struct dirent *de;
- struct stat st;
+static int local_build_list(copyinfo** filelist, const char* lpath, const char* rpath) {
copyinfo *dirlist = 0;
copyinfo *ci, *next;
- d = opendir(lpath);
- if(d == 0) {
- fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
+ std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
+ if (!dir) {
+ fprintf(stderr, "cannot open '%s': %s\n", lpath, strerror(errno));
return -1;
}
- while((de = readdir(d))) {
+ dirent *de;
+ while ((de = readdir(dir.get()))) {
+ if (IsDotOrDotDot(de->d_name)) continue;
+
char stat_path[PATH_MAX];
- char *name = de->d_name;
-
- if(name[0] == '.') {
- if(name[1] == 0) continue;
- if((name[1] == '.') && (name[2] == 0)) continue;
- }
-
- /*
- * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
- * always returns DT_UNKNOWN, so we just use stat() for all cases.
- */
- if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
+ if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
+ fprintf(stderr, "skipping long path '%s%s'\n", lpath, de->d_name);
continue;
+ }
strcpy(stat_path, lpath);
strcat(stat_path, de->d_name);
- if(!lstat(stat_path, &st)) {
+ struct stat st;
+ if (!lstat(stat_path, &st)) {
if (S_ISDIR(st.st_mode)) {
- ci = mkcopyinfo(lpath, rpath, name, 1);
+ ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
ci->next = dirlist;
dirlist = ci;
} else {
- ci = mkcopyinfo(lpath, rpath, name, 0);
- if(lstat(ci->src, &st)) {
- fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
- free(ci);
- closedir(d);
- return -1;
- }
- if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+ ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
+ if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
fprintf(stderr, "skipping special file '%s'\n", ci->src);
free(ci);
} else {
@@ -625,9 +481,9 @@
}
}
- closedir(d);
-
- for(ci = dirlist; ci != 0; ci = next) {
+ // Close this directory and recurse.
+ dir.reset();
+ for (ci = dirlist; ci != 0; ci = next) {
next = ci->next;
local_build_list(filelist, ci->src, ci->dst);
free(ci);
@@ -636,60 +492,55 @@
return 0;
}
-
-static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
-{
+static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
+ bool check_timestamps, bool list_only) {
copyinfo *filelist = 0;
copyinfo *ci, *next;
int pushed = 0;
int skipped = 0;
- if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
- if(lpath[strlen(lpath) - 1] != '/') {
+ if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
+ if (lpath[strlen(lpath) - 1] != '/') {
int tmplen = strlen(lpath)+2;
char *tmp = reinterpret_cast<char*>(malloc(tmplen));
- if(tmp == 0) return -1;
+ if(tmp == 0) return false;
snprintf(tmp, tmplen, "%s/",lpath);
lpath = tmp;
}
- if(rpath[strlen(rpath) - 1] != '/') {
+ if (rpath[strlen(rpath) - 1] != '/') {
int tmplen = strlen(rpath)+2;
char *tmp = reinterpret_cast<char*>(malloc(tmplen));
- if(tmp == 0) return -1;
+ if(tmp == 0) return false;
snprintf(tmp, tmplen, "%s/",rpath);
rpath = tmp;
}
- if(local_build_list(&filelist, lpath, rpath)) {
- return -1;
+ if (local_build_list(&filelist, lpath, rpath)) {
+ return false;
}
- if(checktimestamps){
- for(ci = filelist; ci != 0; ci = ci->next) {
- if(sync_start_readtime(fd, ci->dst)) {
- return 1;
- }
+ if (check_timestamps) {
+ for (ci = filelist; ci != 0; ci = ci->next) {
+ if (!sync_start_stat(sc, ci->dst)) return false;
}
for(ci = filelist; ci != 0; ci = ci->next) {
unsigned int timestamp, mode, size;
- if(sync_finish_readtime(fd, ×tamp, &mode, &size))
- return 1;
- if(size == ci->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))
+ if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
+ (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
ci->flag = 1;
+ }
}
}
}
- for(ci = filelist; ci != 0; ci = next) {
+ for (ci = filelist; ci != 0; ci = next) {
next = ci->next;
- if(ci->flag == 0) {
- fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
- if(!listonly &&
- sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
- 0 /* no show progress */)) {
- return 1;
+ if (ci->flag == 0) {
+ fprintf(stderr, "%spush: %s -> %s\n", list_only ? "would " : "", ci->src, ci->dst);
+ if (!list_only && !sync_send(sc, ci->src, ci->dst, ci->time, ci->mode, false)) {
+ return false;
}
pushed++;
} else {
@@ -698,55 +549,37 @@
free(ci);
}
- fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
+ fprintf(stderr, "%d file%s pushed. %d file%s skipped.\n",
pushed, (pushed == 1) ? "" : "s",
skipped, (skipped == 1) ? "" : "s");
- return 0;
+ return true;
}
-
-int do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
- std::string error;
- int fd = adb_connect("sync:", &error);
- if (fd < 0) {
- fprintf(stderr,"error: %s\n", error.c_str());
- return 1;
- }
+bool do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
+ SyncConnection sc;
+ if (!sc.IsValid()) return false;
struct stat st;
if (stat(lpath, &st)) {
- fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
- sync_quit(fd);
- return 1;
+ fprintf(stderr, "cannot stat '%s': %s\n", lpath, strerror(errno));
+ return false;
}
if (S_ISDIR(st.st_mode)) {
- BEGIN();
- if (copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
- return 1;
- }
- } else {
- unsigned mode;
- if (sync_readmode(fd, rpath, &mode)) {
- return 1;
- }
- std::string path_holder;
- if ((mode != 0) && S_ISDIR(mode)) {
- // If we're copying a local file to a remote directory,
- // we really want to copy to remote_dir + "/" + local_filename.
- path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
- rpath = path_holder.c_str();
- }
- BEGIN();
- if (sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
- return 1;
- }
+ return copy_local_dir_remote(sc, lpath, rpath, false, false);
}
- END();
- sync_quit(fd);
- return 0;
+ unsigned mode;
+ if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
+ std::string path_holder;
+ if (mode != 0 && S_ISDIR(mode)) {
+ // If we're copying a local file to a remote directory,
+ // we really want to copy to remote_dir + "/" + local_filename.
+ path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
+ rpath = path_holder.c_str();
+ }
+ return sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode, show_progress);
}
@@ -766,11 +599,8 @@
if (S_ISDIR(mode)) {
copyinfo **dirlist = args->dirlist;
- /* Don't try recursing down "." or ".." */
- if (name[0] == '.') {
- if (name[1] == '\0') return;
- if ((name[1] == '.') && (name[2] == '\0')) return;
- }
+ // Don't try recursing down "." or "..".
+ if (IsDotOrDotDot(name)) return;
ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
ci->next = *dirlist;
@@ -789,9 +619,8 @@
}
}
-static int remote_build_list(int syncfd, copyinfo **filelist,
- const char *rpath, const char *lpath)
-{
+static bool remote_build_list(int syncfd, copyinfo **filelist,
+ const char *rpath, const char *lpath) {
copyinfo *dirlist = NULL;
sync_ls_build_list_cb_args args;
@@ -800,22 +629,22 @@
args.rpath = rpath;
args.lpath = lpath;
- /* Put the files/dirs in rpath on the lists. */
- if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
- return 1;
+ // Put the files/dirs in rpath on the lists.
+ if (!sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
+ return false;
}
- /* Recurse into each directory we found. */
+ // Recurse into each directory we found.
while (dirlist != NULL) {
copyinfo *next = dirlist->next;
- if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
- return 1;
+ if (!remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
+ return false;
}
free(dirlist);
dirlist = next;
}
- return 0;
+ return true;
}
static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
@@ -831,101 +660,57 @@
return r1 ? : r2;
}
-/* Return a copy of the path string with / appended if needed */
-static char *add_slash_to_path(const char *path)
-{
- if (path[strlen(path) - 1] != '/') {
- size_t len = strlen(path) + 2;
- char *path_with_slash = reinterpret_cast<char*>(malloc(len));
- if (path_with_slash == NULL)
- return NULL;
- snprintf(path_with_slash, len, "%s/", path);
- return path_with_slash;
- } else {
- return strdup(path);
- }
-}
+static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
+ int copy_attrs) {
+ // Make sure that both directory paths end in a slash.
+ std::string rpath_clean(rpath);
+ std::string lpath_clean(lpath);
+ if (rpath_clean.empty() || lpath_clean.empty()) return false;
+ if (rpath_clean.back() != '/') rpath_clean.push_back('/');
+ if (lpath_clean.back() != '/') lpath_clean.push_back('/');
-static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
- int copy_attrs)
-{
- copyinfo *filelist = 0;
- copyinfo *ci, *next;
+ // Recursively build the list of files to copy.
+ fprintf(stderr, "pull: building file list...\n");
+ copyinfo* filelist = nullptr;
+ if (!remote_build_list(sc.fd, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
+
int pulled = 0;
int skipped = 0;
- char *rpath_clean = NULL;
- char *lpath_clean = NULL;
- int ret = 0;
-
- if (rpath[0] == '\0' || lpath[0] == '\0') {
- ret = -1;
- goto finish;
- }
-
- /* Make sure that both directory paths end in a slash. */
- rpath_clean = add_slash_to_path(rpath);
- if (!rpath_clean) {
- ret = -1;
- goto finish;
- }
- lpath_clean = add_slash_to_path(lpath);
- if (!lpath_clean) {
- ret = -1;
- goto finish;
- }
-
- /* Recursively build the list of files to copy. */
- fprintf(stderr, "pull: building file list...\n");
- if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
- ret = -1;
- goto finish;
- }
-
- for (ci = filelist; ci != 0; ci = next) {
- next = ci->next;
+ copyinfo* ci = filelist;
+ while (ci) {
+ copyinfo* next = ci->next;
if (ci->flag == 0) {
fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
- if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
- ret = -1;
- goto finish;
+ if (sync_recv(sc, ci->src, ci->dst, false)) {
+ return false;
}
if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
- ret = -1;
- goto finish;
+ return false;
}
pulled++;
} else {
skipped++;
}
free(ci);
+ ci = next;
}
fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
pulled, (pulled == 1) ? "" : "s",
skipped, (skipped == 1) ? "" : "s");
-
-finish:
- free(lpath_clean);
- free(rpath_clean);
- return ret;
+ return true;
}
-int do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
- std::string error;
- int fd = adb_connect("sync:", &error);
- if (fd < 0) {
- fprintf(stderr,"error: %s\n", error.c_str());
- return 1;
- }
+bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
+ SyncConnection sc;
+ if (!sc.IsValid()) return false;
unsigned mode, time;
- if (sync_readtime(fd, rpath, &time, &mode)) {
- return 1;
- }
+ if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
if (mode == 0) {
- fprintf(stderr,"remote object '%s' does not exist\n", rpath);
- return 1;
+ fprintf(stderr, "remote object '%s' does not exist\n", rpath);
+ return false;
}
if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
@@ -939,44 +724,27 @@
lpath = path_holder.c_str();
}
}
- BEGIN();
- if (sync_recv(fd, rpath, lpath, show_progress)) {
- return 1;
+ if (sync_recv(sc, rpath, lpath, show_progress)) {
+ return false;
} else {
if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
- return 1;
+ return false;
}
}
- } else if(S_ISDIR(mode)) {
- BEGIN();
- if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
- return 1;
- }
- } else {
- fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
- return 1;
+ return true;
+ } else if (S_ISDIR(mode)) {
+ return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
}
- END();
- sync_quit(fd);
- return 0;
+
+ fprintf(stderr, "remote object '%s' not a file or directory\n", rpath);
+ return false;
}
-int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
-{
+bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
fprintf(stderr, "syncing %s...\n", rpath.c_str());
- std::string error;
- int fd = adb_connect("sync:", &error);
- if (fd < 0) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
- }
+ SyncConnection sc;
+ if (!sc.IsValid()) return false;
- BEGIN();
- if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
- return 1;
- }
- END();
- sync_quit(fd);
- return 0;
+ return copy_local_dir_remote(sc, lpath.c_str(), rpath.c_str(), true, list_only);
}