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