file_sync_client.c revision ee878753f915a0176ea411b71bdffde064e24ae0
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                closedir(d);
645                fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
646                return -1;
647            }
648            if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
649                fprintf(stderr, "skipping special file '%s'\n", ci->src);
650                free(ci);
651            } else {
652                ci->time = st.st_mtime;
653                ci->mode = st.st_mode;
654                ci->size = st.st_size;
655                ci->next = *filelist;
656                *filelist = ci;
657            }
658        }
659    }
660
661    closedir(d);
662
663    for(ci = dirlist; ci != 0; ci = next) {
664        next = ci->next;
665        local_build_list(filelist, ci->src, ci->dst);
666        free(ci);
667    }
668
669    return 0;
670}
671
672
673static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
674{
675    copyinfo *filelist = 0;
676    copyinfo *ci, *next;
677    int pushed = 0;
678    int skipped = 0;
679
680    if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
681    if(lpath[strlen(lpath) - 1] != '/') {
682        int  tmplen = strlen(lpath)+2;
683        char *tmp = malloc(tmplen);
684        if(tmp == 0) return -1;
685        snprintf(tmp, tmplen, "%s/",lpath);
686        lpath = tmp;
687    }
688    if(rpath[strlen(rpath) - 1] != '/') {
689        int tmplen = strlen(rpath)+2;
690        char *tmp = malloc(tmplen);
691        if(tmp == 0) return -1;
692        snprintf(tmp, tmplen, "%s/",rpath);
693        rpath = tmp;
694    }
695
696    if(local_build_list(&filelist, lpath, rpath)) {
697        return -1;
698    }
699
700    if(checktimestamps){
701        for(ci = filelist; ci != 0; ci = ci->next) {
702            if(sync_start_readtime(fd, ci->dst)) {
703                return 1;
704            }
705        }
706        for(ci = filelist; ci != 0; ci = ci->next) {
707            unsigned int timestamp, mode, size;
708            if(sync_finish_readtime(fd, &timestamp, &mode, &size))
709                return 1;
710            if(size == ci->size) {
711                /* for links, we cannot update the atime/mtime */
712                if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
713                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
714                    ci->flag = 1;
715            }
716        }
717    }
718    for(ci = filelist; ci != 0; ci = next) {
719        next = ci->next;
720        if(ci->flag == 0) {
721            fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
722            if(!listonly &&
723               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */)){
724                return 1;
725            }
726            pushed++;
727        } else {
728            skipped++;
729        }
730        free(ci);
731    }
732
733    fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
734            pushed, (pushed == 1) ? "" : "s",
735            skipped, (skipped == 1) ? "" : "s");
736
737    return 0;
738}
739
740
741int do_sync_push(const char *lpath, const char *rpath, int verifyApk)
742{
743    struct stat st;
744    unsigned mode;
745    int fd;
746
747    fd = adb_connect("sync:");
748    if(fd < 0) {
749        fprintf(stderr,"error: %s\n", adb_error());
750        return 1;
751    }
752
753    if(stat(lpath, &st)) {
754        fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
755        sync_quit(fd);
756        return 1;
757    }
758
759    if(S_ISDIR(st.st_mode)) {
760        BEGIN();
761        if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
762            return 1;
763        } else {
764            END();
765            sync_quit(fd);
766        }
767    } else {
768        if(sync_readmode(fd, rpath, &mode)) {
769            return 1;
770        }
771        if((mode != 0) && S_ISDIR(mode)) {
772                /* if we're copying a local file to a remote directory,
773                ** we *really* want to copy to remotedir + "/" + localfilename
774                */
775            const char *name = adb_dirstop(lpath);
776            if(name == 0) {
777                name = lpath;
778            } else {
779                name++;
780            }
781            int  tmplen = strlen(name) + strlen(rpath) + 2;
782            char *tmp = malloc(strlen(name) + strlen(rpath) + 2);
783            if(tmp == 0) return 1;
784            snprintf(tmp, tmplen, "%s/%s", rpath, name);
785            rpath = tmp;
786        }
787        BEGIN();
788        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk)) {
789            return 1;
790        } else {
791            END();
792            sync_quit(fd);
793            return 0;
794        }
795    }
796
797    return 0;
798}
799
800
801typedef struct {
802    copyinfo **filelist;
803    copyinfo **dirlist;
804    const char *rpath;
805    const char *lpath;
806} sync_ls_build_list_cb_args;
807
808void
809sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
810                      const char *name, void *cookie)
811{
812    sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
813    copyinfo *ci;
814
815    if (S_ISDIR(mode)) {
816        copyinfo **dirlist = args->dirlist;
817
818        /* Don't try recursing down "." or ".." */
819        if (name[0] == '.') {
820            if (name[1] == '\0') return;
821            if ((name[1] == '.') && (name[2] == '\0')) return;
822        }
823
824        ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
825        ci->next = *dirlist;
826        *dirlist = ci;
827    } else if (S_ISREG(mode) || S_ISLNK(mode)) {
828        copyinfo **filelist = args->filelist;
829
830        ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
831        ci->time = time;
832        ci->mode = mode;
833        ci->size = size;
834        ci->next = *filelist;
835        *filelist = ci;
836    } else {
837        fprintf(stderr, "skipping special file '%s'\n", name);
838    }
839}
840
841static int remote_build_list(int syncfd, copyinfo **filelist,
842                             const char *rpath, const char *lpath)
843{
844    copyinfo *dirlist = NULL;
845    sync_ls_build_list_cb_args args;
846
847    args.filelist = filelist;
848    args.dirlist = &dirlist;
849    args.rpath = rpath;
850    args.lpath = lpath;
851
852    /* Put the files/dirs in rpath on the lists. */
853    if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
854        return 1;
855    }
856
857    /* Recurse into each directory we found. */
858    while (dirlist != NULL) {
859        copyinfo *next = dirlist->next;
860        if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
861            return 1;
862        }
863        free(dirlist);
864        dirlist = next;
865    }
866
867    return 0;
868}
869
870static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
871                                 int checktimestamps)
872{
873    copyinfo *filelist = 0;
874    copyinfo *ci, *next;
875    int pulled = 0;
876    int skipped = 0;
877
878    /* Make sure that both directory paths end in a slash. */
879    if (rpath[0] == 0 || lpath[0] == 0) return -1;
880    if (rpath[strlen(rpath) - 1] != '/') {
881        int  tmplen = strlen(rpath) + 2;
882        char *tmp = malloc(tmplen);
883        if (tmp == 0) return -1;
884        snprintf(tmp, tmplen, "%s/", rpath);
885        rpath = tmp;
886    }
887    if (lpath[strlen(lpath) - 1] != '/') {
888        int  tmplen = strlen(lpath) + 2;
889        char *tmp = malloc(tmplen);
890        if (tmp == 0) return -1;
891        snprintf(tmp, tmplen, "%s/", lpath);
892        lpath = tmp;
893    }
894
895    fprintf(stderr, "pull: building file list...\n");
896    /* Recursively build the list of files to copy. */
897    if (remote_build_list(fd, &filelist, rpath, lpath)) {
898        return -1;
899    }
900
901#if 0
902    if (checktimestamps) {
903        for (ci = filelist; ci != 0; ci = ci->next) {
904            if (sync_start_readtime(fd, ci->dst)) {
905                return 1;
906            }
907        }
908        for (ci = filelist; ci != 0; ci = ci->next) {
909            unsigned int timestamp, mode, size;
910            if (sync_finish_readtime(fd, &timestamp, &mode, &size))
911                return 1;
912            if (size == ci->size) {
913                /* for links, we cannot update the atime/mtime */
914                if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
915                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
916                    ci->flag = 1;
917            }
918        }
919    }
920#endif
921    for (ci = filelist; ci != 0; ci = next) {
922        next = ci->next;
923        if (ci->flag == 0) {
924            fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
925            if (sync_recv(fd, ci->src, ci->dst)) {
926                return 1;
927            }
928            pulled++;
929        } else {
930            skipped++;
931        }
932        free(ci);
933    }
934
935    fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
936            pulled, (pulled == 1) ? "" : "s",
937            skipped, (skipped == 1) ? "" : "s");
938
939    return 0;
940}
941
942int do_sync_pull(const char *rpath, const char *lpath)
943{
944    unsigned mode;
945    struct stat st;
946
947    int fd;
948
949    fd = adb_connect("sync:");
950    if(fd < 0) {
951        fprintf(stderr,"error: %s\n", adb_error());
952        return 1;
953    }
954
955    if(sync_readmode(fd, rpath, &mode)) {
956        return 1;
957    }
958    if(mode == 0) {
959        fprintf(stderr,"remote object '%s' does not exist\n", rpath);
960        return 1;
961    }
962
963    if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
964        if(stat(lpath, &st) == 0) {
965            if(S_ISDIR(st.st_mode)) {
966                    /* if we're copying a remote file to a local directory,
967                    ** we *really* want to copy to localdir + "/" + remotefilename
968                    */
969                const char *name = adb_dirstop(rpath);
970                if(name == 0) {
971                    name = rpath;
972                } else {
973                    name++;
974                }
975                int  tmplen = strlen(name) + strlen(lpath) + 2;
976                char *tmp = malloc(tmplen);
977                if(tmp == 0) return 1;
978                snprintf(tmp, tmplen, "%s/%s", lpath, name);
979                lpath = tmp;
980            }
981        }
982        BEGIN();
983        if(sync_recv(fd, rpath, lpath)) {
984            return 1;
985        } else {
986            END();
987            sync_quit(fd);
988            return 0;
989        }
990    } else if(S_ISDIR(mode)) {
991        BEGIN();
992        if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
993            return 1;
994        } else {
995            END();
996            sync_quit(fd);
997            return 0;
998        }
999    } else {
1000        fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
1001        return 1;
1002    }
1003}
1004
1005int do_sync_sync(const char *lpath, const char *rpath, int listonly)
1006{
1007    fprintf(stderr,"syncing %s...\n",rpath);
1008
1009    int fd = adb_connect("sync:");
1010    if(fd < 0) {
1011        fprintf(stderr,"error: %s\n", adb_error());
1012        return 1;
1013    }
1014
1015    BEGIN();
1016    if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
1017        return 1;
1018    } else {
1019        END();
1020        sync_quit(fd);
1021        return 0;
1022    }
1023}
1024