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