file_sync_client.cpp revision bac3474a8256cb32a29e8d46f78cad95a5502692
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <dirent.h> 18#include <errno.h> 19#include <limits.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <sys/stat.h> 24#include <sys/time.h> 25#include <sys/types.h> 26#include <time.h> 27#include <utime.h> 28 29#include "sysdeps.h" 30 31#include "adb.h" 32#include "adb_client.h" 33#include "adb_io.h" 34#include "file_sync_service.h" 35#include "zipfile/zipfile.h" 36 37static unsigned long long total_bytes; 38static long long start_time; 39 40static long long NOW() 41{ 42 struct timeval tv; 43 gettimeofday(&tv, 0); 44 return ((long long) tv.tv_usec) + 45 1000000LL * ((long long) tv.tv_sec); 46} 47 48static void BEGIN() 49{ 50 total_bytes = 0; 51 start_time = NOW(); 52} 53 54static void END() 55{ 56 long long t = NOW() - start_time; 57 if(total_bytes == 0) return; 58 59 if (t == 0) /* prevent division by 0 :-) */ 60 t = 1000000; 61 62 fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n", 63 ((total_bytes * 1000000LL) / t) / 1024LL, 64 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL); 65} 66 67static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)"; 68 69static void print_transfer_progress(unsigned long long bytes_current, 70 unsigned long long bytes_total) { 71 if (bytes_total == 0) return; 72 73 fprintf(stderr, transfer_progress_format, bytes_current, bytes_total, 74 (int) (bytes_current * 100 / bytes_total)); 75 76 if (bytes_current == bytes_total) { 77 fputc('\n', stderr); 78 } 79 80 fflush(stderr); 81} 82 83void sync_quit(int fd) 84{ 85 syncmsg msg; 86 87 msg.req.id = ID_QUIT; 88 msg.req.namelen = 0; 89 90 WriteFdExactly(fd, &msg.req, sizeof(msg.req)); 91} 92 93typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie); 94 95int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie) 96{ 97 syncmsg msg; 98 char buf[257]; 99 int len; 100 101 len = strlen(path); 102 if(len > 1024) goto fail; 103 104 msg.req.id = ID_LIST; 105 msg.req.namelen = htoll(len); 106 107 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || 108 !WriteFdExactly(fd, path, len)) { 109 goto fail; 110 } 111 112 for(;;) { 113 if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break; 114 if(msg.dent.id == ID_DONE) return 0; 115 if(msg.dent.id != ID_DENT) break; 116 117 len = ltohl(msg.dent.namelen); 118 if(len > 256) break; 119 120 if(!ReadFdExactly(fd, buf, len)) break; 121 buf[len] = 0; 122 123 func(ltohl(msg.dent.mode), 124 ltohl(msg.dent.size), 125 ltohl(msg.dent.time), 126 buf, cookie); 127 } 128 129fail: 130 adb_close(fd); 131 return -1; 132} 133 134typedef struct syncsendbuf syncsendbuf; 135 136struct syncsendbuf { 137 unsigned id; 138 unsigned size; 139 char data[SYNC_DATA_MAX]; 140}; 141 142static syncsendbuf send_buffer; 143 144int sync_readtime(int fd, const char *path, unsigned int *timestamp, 145 unsigned int *mode) 146{ 147 syncmsg msg; 148 int len = strlen(path); 149 150 msg.req.id = ID_STAT; 151 msg.req.namelen = htoll(len); 152 153 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || 154 !WriteFdExactly(fd, path, len)) { 155 return -1; 156 } 157 158 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) { 159 return -1; 160 } 161 162 if(msg.stat.id != ID_STAT) { 163 return -1; 164 } 165 166 *timestamp = ltohl(msg.stat.time); 167 *mode = ltohl(msg.stat.mode); 168 return 0; 169} 170 171static int sync_start_readtime(int fd, const char *path) 172{ 173 syncmsg msg; 174 int len = strlen(path); 175 176 msg.req.id = ID_STAT; 177 msg.req.namelen = htoll(len); 178 179 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || 180 !WriteFdExactly(fd, path, len)) { 181 return -1; 182 } 183 184 return 0; 185} 186 187static int sync_finish_readtime(int fd, unsigned int *timestamp, 188 unsigned int *mode, unsigned int *size) 189{ 190 syncmsg msg; 191 192 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) 193 return -1; 194 195 if(msg.stat.id != ID_STAT) 196 return -1; 197 198 *timestamp = ltohl(msg.stat.time); 199 *mode = ltohl(msg.stat.mode); 200 *size = ltohl(msg.stat.size); 201 202 return 0; 203} 204 205int sync_readmode(int fd, const char *path, unsigned *mode) 206{ 207 syncmsg msg; 208 int len = strlen(path); 209 210 msg.req.id = ID_STAT; 211 msg.req.namelen = htoll(len); 212 213 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || 214 !WriteFdExactly(fd, path, len)) { 215 return -1; 216 } 217 218 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) { 219 return -1; 220 } 221 222 if(msg.stat.id != ID_STAT) { 223 return -1; 224 } 225 226 *mode = ltohl(msg.stat.mode); 227 return 0; 228} 229 230static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress) 231{ 232 int lfd, err = 0; 233 unsigned long long size = 0; 234 235 lfd = adb_open(path, O_RDONLY); 236 if(lfd < 0) { 237 fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno)); 238 return -1; 239 } 240 241 if (show_progress) { 242 // Determine local file size. 243 struct stat st; 244 if (stat(path, &st)) { 245 fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); 246 return -1; 247 } 248 249 size = st.st_size; 250 } 251 252 sbuf->id = ID_DATA; 253 for(;;) { 254 int ret; 255 256 ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX); 257 if(!ret) 258 break; 259 260 if(ret < 0) { 261 if(errno == EINTR) 262 continue; 263 fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno)); 264 break; 265 } 266 267 sbuf->size = htoll(ret); 268 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){ 269 err = -1; 270 break; 271 } 272 total_bytes += ret; 273 274 if (show_progress) { 275 print_transfer_progress(total_bytes, size); 276 } 277 } 278 279 adb_close(lfd); 280 return err; 281} 282 283static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf, 284 int show_progress) 285{ 286 int err = 0; 287 int total = 0; 288 289 sbuf->id = ID_DATA; 290 while (total < size) { 291 int count = size - total; 292 if (count > SYNC_DATA_MAX) { 293 count = SYNC_DATA_MAX; 294 } 295 296 memcpy(sbuf->data, &file_buffer[total], count); 297 sbuf->size = htoll(count); 298 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){ 299 err = -1; 300 break; 301 } 302 total += count; 303 total_bytes += count; 304 305 if (show_progress) { 306 print_transfer_progress(total, size); 307 } 308 } 309 310 return err; 311} 312 313#if defined(_WIN32) 314extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows"))); 315#else 316static int write_data_link(int fd, const char *path, syncsendbuf *sbuf) 317{ 318 int len, ret; 319 320 len = readlink(path, sbuf->data, SYNC_DATA_MAX-1); 321 if(len < 0) { 322 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno)); 323 return -1; 324 } 325 sbuf->data[len] = '\0'; 326 327 sbuf->size = htoll(len + 1); 328 sbuf->id = ID_DATA; 329 330 ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1); 331 if(ret) 332 return -1; 333 334 total_bytes += len + 1; 335 336 return 0; 337} 338#endif 339 340static int sync_send(int fd, const char *lpath, const char *rpath, 341 unsigned mtime, mode_t mode, int show_progress) 342{ 343 syncmsg msg; 344 int len, r; 345 syncsendbuf *sbuf = &send_buffer; 346 char* file_buffer = NULL; 347 int size = 0; 348 char tmp[64]; 349 350 len = strlen(rpath); 351 if(len > 1024) goto fail; 352 353 snprintf(tmp, sizeof(tmp), ",%d", mode); 354 r = strlen(tmp); 355 356 msg.req.id = ID_SEND; 357 msg.req.namelen = htoll(len + r); 358 359 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || 360 !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) { 361 free(file_buffer); 362 goto fail; 363 } 364 365 if (file_buffer) { 366 write_data_buffer(fd, file_buffer, size, sbuf, show_progress); 367 free(file_buffer); 368 } else if (S_ISREG(mode)) 369 write_data_file(fd, lpath, sbuf, show_progress); 370 else if (S_ISLNK(mode)) 371 write_data_link(fd, lpath, sbuf); 372 else 373 goto fail; 374 375 msg.data.id = ID_DONE; 376 msg.data.size = htoll(mtime); 377 if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data))) 378 goto fail; 379 380 if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) 381 return -1; 382 383 if(msg.status.id != ID_OKAY) { 384 if(msg.status.id == ID_FAIL) { 385 len = ltohl(msg.status.msglen); 386 if(len > 256) len = 256; 387 if(!ReadFdExactly(fd, sbuf->data, len)) { 388 return -1; 389 } 390 sbuf->data[len] = 0; 391 } else 392 strcpy(sbuf->data, "unknown reason"); 393 394 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data); 395 return -1; 396 } 397 398 return 0; 399 400fail: 401 fprintf(stderr,"protocol failure\n"); 402 adb_close(fd); 403 return -1; 404} 405 406static int mkdirs(const char *name) 407{ 408 int ret; 409 char *x = (char *)name + 1; 410 411 for(;;) { 412 x = adb_dirstart(x); 413 if(x == 0) return 0; 414 *x = 0; 415 ret = adb_mkdir(name, 0775); 416 *x = OS_PATH_SEPARATOR; 417 if((ret < 0) && (errno != EEXIST)) { 418 return ret; 419 } 420 x++; 421 } 422 return 0; 423} 424 425int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress) 426{ 427 syncmsg msg; 428 int len; 429 int lfd = -1; 430 char *buffer = send_buffer.data; 431 unsigned id; 432 unsigned long long size = 0; 433 434 len = strlen(rpath); 435 if(len > 1024) return -1; 436 437 if (show_progress) { 438 // Determine remote file size. 439 syncmsg stat_msg; 440 stat_msg.req.id = ID_STAT; 441 stat_msg.req.namelen = htoll(len); 442 443 if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) || 444 !WriteFdExactly(fd, rpath, len)) { 445 return -1; 446 } 447 448 if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) { 449 return -1; 450 } 451 452 if (stat_msg.stat.id != ID_STAT) return -1; 453 454 size = ltohl(stat_msg.stat.size); 455 } 456 457 msg.req.id = ID_RECV; 458 msg.req.namelen = htoll(len); 459 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || 460 !WriteFdExactly(fd, rpath, len)) { 461 return -1; 462 } 463 464 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) { 465 return -1; 466 } 467 id = msg.data.id; 468 469 if((id == ID_DATA) || (id == ID_DONE)) { 470 adb_unlink(lpath); 471 mkdirs(lpath); 472 lfd = adb_creat(lpath, 0644); 473 if(lfd < 0) { 474 fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno)); 475 return -1; 476 } 477 goto handle_data; 478 } else { 479 goto remote_error; 480 } 481 482 for(;;) { 483 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) { 484 return -1; 485 } 486 id = msg.data.id; 487 488 handle_data: 489 len = ltohl(msg.data.size); 490 if(id == ID_DONE) break; 491 if(id != ID_DATA) goto remote_error; 492 if(len > SYNC_DATA_MAX) { 493 fprintf(stderr,"data overrun\n"); 494 adb_close(lfd); 495 return -1; 496 } 497 498 if(!ReadFdExactly(fd, buffer, len)) { 499 adb_close(lfd); 500 return -1; 501 } 502 503 if(!WriteFdExactly(lfd, buffer, len)) { 504 fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno)); 505 adb_close(lfd); 506 return -1; 507 } 508 509 total_bytes += len; 510 511 if (show_progress) { 512 print_transfer_progress(total_bytes, size); 513 } 514 } 515 516 adb_close(lfd); 517 return 0; 518 519remote_error: 520 adb_close(lfd); 521 adb_unlink(lpath); 522 523 if(id == ID_FAIL) { 524 len = ltohl(msg.data.size); 525 if(len > 256) len = 256; 526 if(!ReadFdExactly(fd, buffer, len)) { 527 return -1; 528 } 529 buffer[len] = 0; 530 } else { 531 memcpy(buffer, &id, 4); 532 buffer[4] = 0; 533 } 534 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer); 535 return 0; 536} 537 538/* --- */ 539static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time, 540 const char *name, void *cookie) 541{ 542 printf("%08x %08x %08x %s\n", mode, size, time, name); 543} 544 545int do_sync_ls(const char *path) 546{ 547 int fd = adb_connect("sync:"); 548 if(fd < 0) { 549 fprintf(stderr,"error: %s\n", adb_error()); 550 return 1; 551 } 552 553 if(sync_ls(fd, path, do_sync_ls_cb, 0)) { 554 return 1; 555 } else { 556 sync_quit(fd); 557 return 0; 558 } 559} 560 561typedef struct copyinfo copyinfo; 562 563struct copyinfo 564{ 565 copyinfo *next; 566 const char *src; 567 const char *dst; 568 unsigned int time; 569 unsigned int mode; 570 unsigned int size; 571 int flag; 572}; 573 574copyinfo *mkcopyinfo(const char *spath, const char *dpath, 575 const char *name, int isdir) 576{ 577 int slen = strlen(spath); 578 int dlen = strlen(dpath); 579 int nlen = strlen(name); 580 int ssize = slen + nlen + 2; 581 int dsize = dlen + nlen + 2; 582 583 copyinfo *ci = reinterpret_cast<copyinfo*>( 584 malloc(sizeof(copyinfo) + ssize + dsize)); 585 if(ci == 0) { 586 fprintf(stderr,"out of memory\n"); 587 abort(); 588 } 589 590 ci->next = 0; 591 ci->time = 0; 592 ci->mode = 0; 593 ci->size = 0; 594 ci->flag = 0; 595 ci->src = (const char*)(ci + 1); 596 ci->dst = ci->src + ssize; 597 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name); 598 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name); 599 600 return ci; 601} 602 603 604static int local_build_list(copyinfo **filelist, 605 const char *lpath, const char *rpath) 606{ 607 DIR *d; 608 struct dirent *de; 609 struct stat st; 610 copyinfo *dirlist = 0; 611 copyinfo *ci, *next; 612 613 d = opendir(lpath); 614 if(d == 0) { 615 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno)); 616 return -1; 617 } 618 619 while((de = readdir(d))) { 620 char stat_path[PATH_MAX]; 621 char *name = de->d_name; 622 623 if(name[0] == '.') { 624 if(name[1] == 0) continue; 625 if((name[1] == '.') && (name[2] == 0)) continue; 626 } 627 628 /* 629 * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs 630 * always returns DT_UNKNOWN, so we just use stat() for all cases. 631 */ 632 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) 633 continue; 634 strcpy(stat_path, lpath); 635 strcat(stat_path, de->d_name); 636 637 if(!lstat(stat_path, &st)) { 638 if (S_ISDIR(st.st_mode)) { 639 ci = mkcopyinfo(lpath, rpath, name, 1); 640 ci->next = dirlist; 641 dirlist = ci; 642 } else { 643 ci = mkcopyinfo(lpath, rpath, name, 0); 644 if(lstat(ci->src, &st)) { 645 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno)); 646 free(ci); 647 closedir(d); 648 return -1; 649 } 650 if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { 651 fprintf(stderr, "skipping special file '%s'\n", ci->src); 652 free(ci); 653 } else { 654 ci->time = st.st_mtime; 655 ci->mode = st.st_mode; 656 ci->size = st.st_size; 657 ci->next = *filelist; 658 *filelist = ci; 659 } 660 } 661 } else { 662 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno)); 663 } 664 } 665 666 closedir(d); 667 668 for(ci = dirlist; ci != 0; ci = next) { 669 next = ci->next; 670 local_build_list(filelist, ci->src, ci->dst); 671 free(ci); 672 } 673 674 return 0; 675} 676 677 678static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly) 679{ 680 copyinfo *filelist = 0; 681 copyinfo *ci, *next; 682 int pushed = 0; 683 int skipped = 0; 684 685 if((lpath[0] == 0) || (rpath[0] == 0)) return -1; 686 if(lpath[strlen(lpath) - 1] != '/') { 687 int tmplen = strlen(lpath)+2; 688 char *tmp = reinterpret_cast<char*>(malloc(tmplen)); 689 if(tmp == 0) return -1; 690 snprintf(tmp, tmplen, "%s/",lpath); 691 lpath = tmp; 692 } 693 if(rpath[strlen(rpath) - 1] != '/') { 694 int tmplen = strlen(rpath)+2; 695 char *tmp = reinterpret_cast<char*>(malloc(tmplen)); 696 if(tmp == 0) return -1; 697 snprintf(tmp, tmplen, "%s/",rpath); 698 rpath = tmp; 699 } 700 701 if(local_build_list(&filelist, lpath, rpath)) { 702 return -1; 703 } 704 705 if(checktimestamps){ 706 for(ci = filelist; ci != 0; ci = ci->next) { 707 if(sync_start_readtime(fd, ci->dst)) { 708 return 1; 709 } 710 } 711 for(ci = filelist; ci != 0; ci = ci->next) { 712 unsigned int timestamp, mode, size; 713 if(sync_finish_readtime(fd, ×tamp, &mode, &size)) 714 return 1; 715 if(size == ci->size) { 716 /* for links, we cannot update the atime/mtime */ 717 if((S_ISREG(ci->mode & mode) && timestamp == ci->time) || 718 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) 719 ci->flag = 1; 720 } 721 } 722 } 723 for(ci = filelist; ci != 0; ci = next) { 724 next = ci->next; 725 if(ci->flag == 0) { 726 fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst); 727 if(!listonly && 728 sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 729 0 /* no show progress */)) { 730 return 1; 731 } 732 pushed++; 733 } else { 734 skipped++; 735 } 736 free(ci); 737 } 738 739 fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n", 740 pushed, (pushed == 1) ? "" : "s", 741 skipped, (skipped == 1) ? "" : "s"); 742 743 return 0; 744} 745 746 747int do_sync_push(const char *lpath, const char *rpath, int show_progress) 748{ 749 struct stat st; 750 unsigned mode; 751 int fd; 752 753 fd = adb_connect("sync:"); 754 if(fd < 0) { 755 fprintf(stderr,"error: %s\n", adb_error()); 756 return 1; 757 } 758 759 if(stat(lpath, &st)) { 760 fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno)); 761 sync_quit(fd); 762 return 1; 763 } 764 765 if(S_ISDIR(st.st_mode)) { 766 BEGIN(); 767 if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) { 768 return 1; 769 } else { 770 END(); 771 sync_quit(fd); 772 } 773 } else { 774 if(sync_readmode(fd, rpath, &mode)) { 775 return 1; 776 } 777 if((mode != 0) && S_ISDIR(mode)) { 778 /* if we're copying a local file to a remote directory, 779 ** we *really* want to copy to remotedir + "/" + localfilename 780 */ 781 const char *name = adb_dirstop(lpath); 782 if(name == 0) { 783 name = lpath; 784 } else { 785 name++; 786 } 787 int tmplen = strlen(name) + strlen(rpath) + 2; 788 char *tmp = reinterpret_cast<char*>( 789 malloc(strlen(name) + strlen(rpath) + 2)); 790 if(tmp == 0) return 1; 791 snprintf(tmp, tmplen, "%s/%s", rpath, name); 792 rpath = tmp; 793 } 794 BEGIN(); 795 if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) { 796 return 1; 797 } else { 798 END(); 799 sync_quit(fd); 800 return 0; 801 } 802 } 803 804 return 0; 805} 806 807 808typedef struct { 809 copyinfo **filelist; 810 copyinfo **dirlist; 811 const char *rpath; 812 const char *lpath; 813} sync_ls_build_list_cb_args; 814 815void 816sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time, 817 const char *name, void *cookie) 818{ 819 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie; 820 copyinfo *ci; 821 822 if (S_ISDIR(mode)) { 823 copyinfo **dirlist = args->dirlist; 824 825 /* Don't try recursing down "." or ".." */ 826 if (name[0] == '.') { 827 if (name[1] == '\0') return; 828 if ((name[1] == '.') && (name[2] == '\0')) return; 829 } 830 831 ci = mkcopyinfo(args->rpath, args->lpath, name, 1); 832 ci->next = *dirlist; 833 *dirlist = ci; 834 } else if (S_ISREG(mode) || S_ISLNK(mode)) { 835 copyinfo **filelist = args->filelist; 836 837 ci = mkcopyinfo(args->rpath, args->lpath, name, 0); 838 ci->time = time; 839 ci->mode = mode; 840 ci->size = size; 841 ci->next = *filelist; 842 *filelist = ci; 843 } else { 844 fprintf(stderr, "skipping special file '%s'\n", name); 845 } 846} 847 848static int remote_build_list(int syncfd, copyinfo **filelist, 849 const char *rpath, const char *lpath) 850{ 851 copyinfo *dirlist = NULL; 852 sync_ls_build_list_cb_args args; 853 854 args.filelist = filelist; 855 args.dirlist = &dirlist; 856 args.rpath = rpath; 857 args.lpath = lpath; 858 859 /* Put the files/dirs in rpath on the lists. */ 860 if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) { 861 return 1; 862 } 863 864 /* Recurse into each directory we found. */ 865 while (dirlist != NULL) { 866 copyinfo *next = dirlist->next; 867 if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) { 868 return 1; 869 } 870 free(dirlist); 871 dirlist = next; 872 } 873 874 return 0; 875} 876 877static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode) 878{ 879 struct utimbuf times = { time, time }; 880 int r1 = utime(lpath, ×); 881 882 /* use umask for permissions */ 883 mode_t mask=umask(0000); 884 umask(mask); 885 int r2 = chmod(lpath, mode & ~mask); 886 887 return r1 ? : r2; 888} 889 890/* Return a copy of the path string with / appended if needed */ 891static char *add_slash_to_path(const char *path) 892{ 893 if (path[strlen(path) - 1] != '/') { 894 size_t len = strlen(path) + 2; 895 char *path_with_slash = reinterpret_cast<char*>(malloc(len)); 896 if (path_with_slash == NULL) 897 return NULL; 898 snprintf(path_with_slash, len, "%s/", path); 899 return path_with_slash; 900 } else { 901 return strdup(path); 902 } 903} 904 905static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, 906 int copy_attrs) 907{ 908 copyinfo *filelist = 0; 909 copyinfo *ci, *next; 910 int pulled = 0; 911 int skipped = 0; 912 char *rpath_clean = NULL; 913 char *lpath_clean = NULL; 914 int ret = 0; 915 916 if (rpath[0] == '\0' || lpath[0] == '\0') { 917 ret = -1; 918 goto finish; 919 } 920 921 /* Make sure that both directory paths end in a slash. */ 922 rpath_clean = add_slash_to_path(rpath); 923 if (!rpath_clean) { 924 ret = -1; 925 goto finish; 926 } 927 lpath_clean = add_slash_to_path(lpath); 928 if (!lpath_clean) { 929 ret = -1; 930 goto finish; 931 } 932 933 /* Recursively build the list of files to copy. */ 934 fprintf(stderr, "pull: building file list...\n"); 935 if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) { 936 ret = -1; 937 goto finish; 938 } 939 940 for (ci = filelist; ci != 0; ci = next) { 941 next = ci->next; 942 if (ci->flag == 0) { 943 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst); 944 if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) { 945 ret = -1; 946 goto finish; 947 } 948 949 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) { 950 ret = -1; 951 goto finish; 952 } 953 pulled++; 954 } else { 955 skipped++; 956 } 957 free(ci); 958 } 959 960 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n", 961 pulled, (pulled == 1) ? "" : "s", 962 skipped, (skipped == 1) ? "" : "s"); 963 964finish: 965 free(lpath_clean); 966 free(rpath_clean); 967 return ret; 968} 969 970int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs) 971{ 972 unsigned mode, time; 973 struct stat st; 974 975 int fd; 976 977 fd = adb_connect("sync:"); 978 if(fd < 0) { 979 fprintf(stderr,"error: %s\n", adb_error()); 980 return 1; 981 } 982 983 if(sync_readtime(fd, rpath, &time, &mode)) { 984 return 1; 985 } 986 if(mode == 0) { 987 fprintf(stderr,"remote object '%s' does not exist\n", rpath); 988 return 1; 989 } 990 991 if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) { 992 if(stat(lpath, &st) == 0) { 993 if(S_ISDIR(st.st_mode)) { 994 /* if we're copying a remote file to a local directory, 995 ** we *really* want to copy to localdir + "/" + remotefilename 996 */ 997 const char *name = adb_dirstop(rpath); 998 if(name == 0) { 999 name = rpath; 1000 } else { 1001 name++; 1002 } 1003 int tmplen = strlen(name) + strlen(lpath) + 2; 1004 char *tmp = reinterpret_cast<char*>(malloc(tmplen)); 1005 if(tmp == 0) return 1; 1006 snprintf(tmp, tmplen, "%s/%s", lpath, name); 1007 lpath = tmp; 1008 } 1009 } 1010 BEGIN(); 1011 if (sync_recv(fd, rpath, lpath, show_progress)) { 1012 return 1; 1013 } else { 1014 if (copy_attrs && set_time_and_mode(lpath, time, mode)) 1015 return 1; 1016 END(); 1017 sync_quit(fd); 1018 return 0; 1019 } 1020 } else if(S_ISDIR(mode)) { 1021 BEGIN(); 1022 if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) { 1023 return 1; 1024 } else { 1025 END(); 1026 sync_quit(fd); 1027 return 0; 1028 } 1029 } else { 1030 fprintf(stderr,"remote object '%s' not a file or directory\n", rpath); 1031 return 1; 1032 } 1033} 1034 1035int do_sync_sync(const char *lpath, const char *rpath, int listonly) 1036{ 1037 fprintf(stderr,"syncing %s...\n",rpath); 1038 1039 int fd = adb_connect("sync:"); 1040 if(fd < 0) { 1041 fprintf(stderr,"error: %s\n", adb_error()); 1042 return 1; 1043 } 1044 1045 BEGIN(); 1046 if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){ 1047 return 1; 1048 } else { 1049 END(); 1050 sync_quit(fd); 1051 return 0; 1052 } 1053} 1054