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