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