From 76f2a93b18e0d321d527cb64c2b2c4281e1cf70f Mon Sep 17 00:00:00 2001 From: Mark Lindner Date: Tue, 11 Mar 2014 17:55:59 -0700 Subject: [PATCH] Added transfer progress reporting for push and pull commands. Added a new '-p' switch to the 'push' and 'pull' commands that outputs the file transfer progress (bytes transmitted, total bytes, and % done). This provides useful feedback when transferring large files, and also makes it possible for other tools to easily monitor the progress of a forked push/pull command. Change-Id: Iee6f42f5bd41292e5bc80fba779f526f0072e356 --- adb/commandline.c | 62 +++++++++++++++++++++++------ adb/file_sync_client.c | 87 +++++++++++++++++++++++++++++++++++------ adb/file_sync_service.h | 6 +-- 3 files changed, 128 insertions(+), 27 deletions(-) diff --git a/adb/commandline.c b/adb/commandline.c index c9bb43749..83b568d96 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -107,8 +107,12 @@ void help() " will disconnect from all connected TCP/IP devices.\n" "\n" "device commands:\n" - " adb push - copy file/dir to device\n" - " adb pull [] - copy file/dir from device\n" + " adb push [-p] \n" + " - copy file/dir to device\n" + " ('-p' to display the transfer progress)\n" + " adb pull [-p] []\n" + " - copy file/dir from device\n" + " ('-p' to display the transfer progress)\n" " adb sync [ ] - copy host->device only if changed\n" " (-l means list but don't copy)\n" " (see 'adb help all')\n" @@ -921,6 +925,28 @@ static const char *find_product_out_path(const char *hint) return path_buf; } + +static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2, + int* show_progress) { + *show_progress = 0; + + if ((narg > 0) && !strcmp(*arg, "-p")) { + *show_progress = 1; + ++arg; + --narg; + } + + if (narg > 0) { + *path1 = *arg; + ++arg; + --narg; + } + + if (narg > 0) { + *path2 = *arg; + } +} + int adb_commandline(int argc, char **argv) { char buf[4096]; @@ -1368,18 +1394,29 @@ top: } if(!strcmp(argv[0], "push")) { - if(argc != 3) return usage(); - return do_sync_push(argv[1], argv[2], 0 /* no verify APK */); + int show_progress = 0; + const char* lpath = NULL, *rpath = NULL; + + parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress); + + if ((lpath != NULL) && (rpath != NULL)) { + return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress); + } + + return usage(); } if(!strcmp(argv[0], "pull")) { - if (argc == 2) { - return do_sync_pull(argv[1], "."); - } else if (argc == 3) { - return do_sync_pull(argv[1], argv[2]); - } else { - return usage(); + int show_progress = 0; + const char* rpath = NULL, *lpath = "."; + + parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress); + + if (rpath != NULL) { + return do_sync_pull(rpath, lpath, show_progress); } + + return usage(); } if(!strcmp(argv[0], "install")) { @@ -1717,7 +1754,7 @@ int install_app(transport_type transport, char* serial, int argc, char** argv) } } - err = do_sync_push(apk_file, apk_dest, verify_apk); + err = do_sync_push(apk_file, apk_dest, verify_apk, 0 /* no show progress */); if (err) { goto cleanup_apk; } else { @@ -1725,7 +1762,8 @@ int install_app(transport_type transport, char* serial, int argc, char** argv) } if (verification_file != NULL) { - err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */); + err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */, + 0 /* no show progress */); if (err) { goto cleanup_apk; } else { diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c index 9fec081d0..8fad50e01 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.c @@ -62,6 +62,22 @@ static void END() total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL); } +static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)"; + +static void print_transfer_progress(unsigned long long bytes_current, + unsigned long long bytes_total) { + if (bytes_total == 0) return; + + fprintf(stderr, transfer_progress_format, bytes_current, bytes_total, + (int) (bytes_current * 100 / bytes_total)); + + if (bytes_current == bytes_total) { + fputc('\n', stderr); + } + + fflush(stderr); +} + void sync_quit(int fd) { syncmsg msg; @@ -207,9 +223,10 @@ int sync_readmode(int fd, const char *path, unsigned *mode) return 0; } -static int write_data_file(int fd, const char *path, syncsendbuf *sbuf) +static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress) { int lfd, err = 0; + unsigned long long size = 0; lfd = adb_open(path, O_RDONLY); if(lfd < 0) { @@ -217,6 +234,17 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf) return -1; } + if (show_progress) { + // Determine local file size. + struct stat st; + if (lstat(path, &st)) { + fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); + return -1; + } + + size = st.st_size; + } + sbuf->id = ID_DATA; for(;;) { int ret; @@ -238,13 +266,18 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf) break; } total_bytes += ret; + + if (show_progress) { + print_transfer_progress(total_bytes, size); + } } adb_close(lfd); return err; } -static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf) +static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf, + int show_progress) { int err = 0; int total = 0; @@ -264,6 +297,10 @@ static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *s } total += count; total_bytes += count; + + if (show_progress) { + print_transfer_progress(total, size); + } } return err; @@ -295,7 +332,7 @@ static int write_data_link(int fd, const char *path, syncsendbuf *sbuf) #endif static int sync_send(int fd, const char *lpath, const char *rpath, - unsigned mtime, mode_t mode, int verifyApk) + unsigned mtime, mode_t mode, int verifyApk, int show_progress) { syncmsg msg; int len, r; @@ -377,10 +414,10 @@ static int sync_send(int fd, const char *lpath, const char *rpath, } if (file_buffer) { - write_data_buffer(fd, file_buffer, size, sbuf); + write_data_buffer(fd, file_buffer, size, sbuf, show_progress); free(file_buffer); } else if (S_ISREG(mode)) - write_data_file(fd, lpath, sbuf); + write_data_file(fd, lpath, sbuf, show_progress); #ifdef HAVE_SYMLINKS else if (S_ISLNK(mode)) write_data_link(fd, lpath, sbuf); @@ -438,17 +475,38 @@ static int mkdirs(char *name) return 0; } -int sync_recv(int fd, const char *rpath, const char *lpath) +int sync_recv(int fd, const char *rpath, const char *lpath, int 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; + if (show_progress) { + // Determine remote file size. + syncmsg stat_msg; + stat_msg.req.id = ID_STAT; + stat_msg.req.namelen = htoll(len); + + if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) || + writex(fd, rpath, len)) { + return -1; + } + + if (readx(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); + } + msg.req.id = ID_RECV; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || @@ -502,6 +560,10 @@ int sync_recv(int fd, const char *rpath, const char *lpath) } total_bytes += len; + + if (show_progress) { + print_transfer_progress(total_bytes, size); + } } adb_close(lfd); @@ -721,7 +783,8 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i 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 verify APK */)){ + sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */, + 0 /* no show progress */)) { return 1; } pushed++; @@ -739,7 +802,7 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i } -int do_sync_push(const char *lpath, const char *rpath, int verifyApk) +int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress) { struct stat st; unsigned mode; @@ -786,7 +849,7 @@ int do_sync_push(const char *lpath, const char *rpath, int verifyApk) rpath = tmp; } BEGIN(); - if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk)) { + if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk, show_progress)) { return 1; } else { END(); @@ -923,7 +986,7 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, 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)) { + if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) { return 1; } pulled++; @@ -940,7 +1003,7 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, return 0; } -int do_sync_pull(const char *rpath, const char *lpath) +int do_sync_pull(const char *rpath, const char *lpath, int show_progress) { unsigned mode; struct stat st; @@ -981,7 +1044,7 @@ int do_sync_pull(const char *rpath, const char *lpath) } } BEGIN(); - if(sync_recv(fd, rpath, lpath)) { + if (sync_recv(fd, rpath, lpath, show_progress)) { return 1; } else { END(); diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h index e402e0682..3e7e096c1 100644 --- a/adb/file_sync_service.h +++ b/adb/file_sync_service.h @@ -72,15 +72,15 @@ typedef union { struct { unsigned id; unsigned msglen; - } status; + } status; } syncmsg; void file_sync_service(int fd, void *cookie); int do_sync_ls(const char *path); -int do_sync_push(const char *lpath, const char *rpath, int verifyApk); +int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress); int do_sync_sync(const char *lpath, const char *rpath, int listonly); -int do_sync_pull(const char *rpath, const char *lpath); +int do_sync_pull(const char *rpath, const char *lpath, int show_progress); #define SYNC_DATA_MAX (64*1024)