file_sync_client.cpp revision 2d4121c0dcc93382bcd7ea6476f433d8254919dd
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 <dirent.h>
18#include <errno.h>
19#include <limits.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/stat.h>
24#include <sys/time.h>
25#include <sys/types.h>
26#include <time.h>
27#include <utime.h>
28
29#include "sysdeps.h"
30
31#include "adb.h"
32#include "adb_client.h"
33#include "adb_io.h"
34#include "file_sync_service.h"
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    WriteFdExactly(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(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
107       !WriteFdExactly(fd, path, len)) {
108        goto fail;
109    }
110
111    for(;;) {
112        if(!ReadFdExactly(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(!ReadFdExactly(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
133struct syncsendbuf {
134    unsigned id;
135    unsigned size;
136    char data[SYNC_DATA_MAX];
137};
138
139static syncsendbuf send_buffer;
140
141int sync_readtime(int fd, const char *path, unsigned int *timestamp,
142                  unsigned int *mode)
143{
144    syncmsg msg;
145    int len = strlen(path);
146
147    msg.req.id = ID_STAT;
148    msg.req.namelen = htoll(len);
149
150    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
151       !WriteFdExactly(fd, path, len)) {
152        return -1;
153    }
154
155    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
156        return -1;
157    }
158
159    if(msg.stat.id != ID_STAT) {
160        return -1;
161    }
162
163    *timestamp = ltohl(msg.stat.time);
164    *mode = ltohl(msg.stat.mode);
165    return 0;
166}
167
168static int sync_start_readtime(int fd, const char *path)
169{
170    syncmsg msg;
171    int len = strlen(path);
172
173    msg.req.id = ID_STAT;
174    msg.req.namelen = htoll(len);
175
176    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
177       !WriteFdExactly(fd, path, len)) {
178        return -1;
179    }
180
181    return 0;
182}
183
184static int sync_finish_readtime(int fd, unsigned int *timestamp,
185                                unsigned int *mode, unsigned int *size)
186{
187    syncmsg msg;
188
189    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
190        return -1;
191
192    if(msg.stat.id != ID_STAT)
193        return -1;
194
195    *timestamp = ltohl(msg.stat.time);
196    *mode = ltohl(msg.stat.mode);
197    *size = ltohl(msg.stat.size);
198
199    return 0;
200}
201
202int sync_readmode(int fd, const char *path, unsigned *mode)
203{
204    syncmsg msg;
205    int len = strlen(path);
206
207    msg.req.id = ID_STAT;
208    msg.req.namelen = htoll(len);
209
210    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
211       !WriteFdExactly(fd, path, len)) {
212        return -1;
213    }
214
215    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
216        return -1;
217    }
218
219    if(msg.stat.id != ID_STAT) {
220        return -1;
221    }
222
223    *mode = ltohl(msg.stat.mode);
224    return 0;
225}
226
227static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
228{
229    int lfd, err = 0;
230    unsigned long long size = 0;
231
232    lfd = adb_open(path, O_RDONLY);
233    if(lfd < 0) {
234        fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
235        return -1;
236    }
237
238    if (show_progress) {
239        // Determine local file size.
240        struct stat st;
241        if (stat(path, &st)) {
242            fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
243            return -1;
244        }
245
246        size = st.st_size;
247    }
248
249    sbuf->id = ID_DATA;
250    for(;;) {
251        int ret;
252
253        ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
254        if(!ret)
255            break;
256
257        if(ret < 0) {
258            if(errno == EINTR)
259                continue;
260            fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
261            break;
262        }
263
264        sbuf->size = htoll(ret);
265        if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
266            err = -1;
267            break;
268        }
269        total_bytes += ret;
270
271        if (show_progress) {
272            print_transfer_progress(total_bytes, size);
273        }
274    }
275
276    adb_close(lfd);
277    return err;
278}
279
280static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
281                             int show_progress)
282{
283    int err = 0;
284    int total = 0;
285
286    sbuf->id = ID_DATA;
287    while (total < size) {
288        int count = size - total;
289        if (count > SYNC_DATA_MAX) {
290            count = SYNC_DATA_MAX;
291        }
292
293        memcpy(sbuf->data, &file_buffer[total], count);
294        sbuf->size = htoll(count);
295        if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
296            err = -1;
297            break;
298        }
299        total += count;
300        total_bytes += count;
301
302        if (show_progress) {
303            print_transfer_progress(total, size);
304        }
305    }
306
307    return err;
308}
309
310#if defined(_WIN32)
311extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
312#else
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 = !WriteFdExactly(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(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
357       !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(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    else if (S_ISLNK(mode))
368        write_data_link(fd, lpath, sbuf);
369    else
370        goto fail;
371
372    msg.data.id = ID_DONE;
373    msg.data.size = htoll(mtime);
374    if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
375        goto fail;
376
377    if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
378        return -1;
379
380    if(msg.status.id != ID_OKAY) {
381        if(msg.status.id == ID_FAIL) {
382            len = ltohl(msg.status.msglen);
383            if(len > 256) len = 256;
384            if(!ReadFdExactly(fd, sbuf->data, len)) {
385                return -1;
386            }
387            sbuf->data[len] = 0;
388        } else
389            strcpy(sbuf->data, "unknown reason");
390
391        fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
392        return -1;
393    }
394
395    return 0;
396
397fail:
398    fprintf(stderr,"protocol failure\n");
399    adb_close(fd);
400    return -1;
401}
402
403static int mkdirs(const char *name)
404{
405    int ret;
406    char *x = (char *)name + 1;
407
408    for(;;) {
409        x = adb_dirstart(x);
410        if(x == 0) return 0;
411        *x = 0;
412        ret = adb_mkdir(name, 0775);
413        *x = OS_PATH_SEPARATOR;
414        if((ret < 0) && (errno != EEXIST)) {
415            return ret;
416        }
417        x++;
418    }
419    return 0;
420}
421
422int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
423{
424    syncmsg msg;
425    int len;
426    int lfd = -1;
427    char *buffer = send_buffer.data;
428    unsigned id;
429    unsigned long long size = 0;
430
431    len = strlen(rpath);
432    if(len > 1024) return -1;
433
434    if (show_progress) {
435        // Determine remote file size.
436        syncmsg stat_msg;
437        stat_msg.req.id = ID_STAT;
438        stat_msg.req.namelen = htoll(len);
439
440        if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
441            !WriteFdExactly(fd, rpath, len)) {
442            return -1;
443        }
444
445        if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
446            return -1;
447        }
448
449        if (stat_msg.stat.id != ID_STAT) return -1;
450
451        size = ltohl(stat_msg.stat.size);
452    }
453
454    msg.req.id = ID_RECV;
455    msg.req.namelen = htoll(len);
456    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
457       !WriteFdExactly(fd, rpath, len)) {
458        return -1;
459    }
460
461    if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
462        return -1;
463    }
464    id = msg.data.id;
465
466    if((id == ID_DATA) || (id == ID_DONE)) {
467        adb_unlink(lpath);
468        mkdirs(lpath);
469        lfd = adb_creat(lpath, 0644);
470        if(lfd < 0) {
471            fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
472            return -1;
473        }
474        goto handle_data;
475    } else {
476        goto remote_error;
477    }
478
479    for(;;) {
480        if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
481            return -1;
482        }
483        id = msg.data.id;
484
485    handle_data:
486        len = ltohl(msg.data.size);
487        if(id == ID_DONE) break;
488        if(id != ID_DATA) goto remote_error;
489        if(len > SYNC_DATA_MAX) {
490            fprintf(stderr,"data overrun\n");
491            adb_close(lfd);
492            return -1;
493        }
494
495        if(!ReadFdExactly(fd, buffer, len)) {
496            adb_close(lfd);
497            return -1;
498        }
499
500        if(!WriteFdExactly(lfd, buffer, len)) {
501            fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
502            adb_close(lfd);
503            return -1;
504        }
505
506        total_bytes += len;
507
508        if (show_progress) {
509            print_transfer_progress(total_bytes, size);
510        }
511    }
512
513    adb_close(lfd);
514    return 0;
515
516remote_error:
517    adb_close(lfd);
518    adb_unlink(lpath);
519
520    if(id == ID_FAIL) {
521        len = ltohl(msg.data.size);
522        if(len > 256) len = 256;
523        if(!ReadFdExactly(fd, buffer, len)) {
524            return -1;
525        }
526        buffer[len] = 0;
527    } else {
528        memcpy(buffer, &id, 4);
529        buffer[4] = 0;
530    }
531    fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
532    return 0;
533}
534
535/* --- */
536static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
537                          const char *name, void *cookie)
538{
539    printf("%08x %08x %08x %s\n", mode, size, time, name);
540}
541
542int do_sync_ls(const char *path)
543{
544    int fd = adb_connect("sync:");
545    if(fd < 0) {
546        fprintf(stderr,"error: %s\n", adb_error());
547        return 1;
548    }
549
550    if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
551        return 1;
552    } else {
553        sync_quit(fd);
554        return 0;
555    }
556}
557
558struct copyinfo
559{
560    copyinfo *next;
561    const char *src;
562    const char *dst;
563    unsigned int time;
564    unsigned int mode;
565    unsigned int size;
566    int flag;
567};
568
569copyinfo *mkcopyinfo(const char *spath, const char *dpath,
570                     const char *name, int isdir)
571{
572    int slen = strlen(spath);
573    int dlen = strlen(dpath);
574    int nlen = strlen(name);
575    int ssize = slen + nlen + 2;
576    int dsize = dlen + nlen + 2;
577
578    copyinfo *ci = reinterpret_cast<copyinfo*>(
579        malloc(sizeof(copyinfo) + ssize + dsize));
580    if(ci == 0) {
581        fprintf(stderr,"out of memory\n");
582        abort();
583    }
584
585    ci->next = 0;
586    ci->time = 0;
587    ci->mode = 0;
588    ci->size = 0;
589    ci->flag = 0;
590    ci->src = (const char*)(ci + 1);
591    ci->dst = ci->src + ssize;
592    snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
593    snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
594
595    return ci;
596}
597
598
599static int local_build_list(copyinfo **filelist,
600                            const char *lpath, const char *rpath)
601{
602    DIR *d;
603    struct dirent *de;
604    struct stat st;
605    copyinfo *dirlist = 0;
606    copyinfo *ci, *next;
607
608    d = opendir(lpath);
609    if(d == 0) {
610        fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
611        return -1;
612    }
613
614    while((de = readdir(d))) {
615        char stat_path[PATH_MAX];
616        char *name = de->d_name;
617
618        if(name[0] == '.') {
619            if(name[1] == 0) continue;
620            if((name[1] == '.') && (name[2] == 0)) continue;
621        }
622
623        /*
624         * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
625         * always returns DT_UNKNOWN, so we just use stat() for all cases.
626         */
627        if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
628            continue;
629        strcpy(stat_path, lpath);
630        strcat(stat_path, de->d_name);
631
632        if(!lstat(stat_path, &st)) {
633            if (S_ISDIR(st.st_mode)) {
634                ci = mkcopyinfo(lpath, rpath, name, 1);
635                ci->next = dirlist;
636                dirlist = ci;
637            } else {
638                ci = mkcopyinfo(lpath, rpath, name, 0);
639                if(lstat(ci->src, &st)) {
640                    fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
641                    free(ci);
642                    closedir(d);
643                    return -1;
644                }
645                if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
646                    fprintf(stderr, "skipping special file '%s'\n", ci->src);
647                    free(ci);
648                } else {
649                    ci->time = st.st_mtime;
650                    ci->mode = st.st_mode;
651                    ci->size = st.st_size;
652                    ci->next = *filelist;
653                    *filelist = ci;
654                }
655            }
656        } else {
657            fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
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 = reinterpret_cast<char*>(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 = reinterpret_cast<char*>(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,
724                         0 /* no show progress */)) {
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 show_progress)
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 = reinterpret_cast<char*>(
784                malloc(strlen(name) + strlen(rpath) + 2));
785            if(tmp == 0) return 1;
786            snprintf(tmp, tmplen, "%s/%s", rpath, name);
787            rpath = tmp;
788        }
789        BEGIN();
790        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
791            return 1;
792        } else {
793            END();
794            sync_quit(fd);
795            return 0;
796        }
797    }
798
799    return 0;
800}
801
802
803struct sync_ls_build_list_cb_args {
804    copyinfo **filelist;
805    copyinfo **dirlist;
806    const char *rpath;
807    const char *lpath;
808};
809
810void
811sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
812                      const char *name, void *cookie)
813{
814    sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
815    copyinfo *ci;
816
817    if (S_ISDIR(mode)) {
818        copyinfo **dirlist = args->dirlist;
819
820        /* Don't try recursing down "." or ".." */
821        if (name[0] == '.') {
822            if (name[1] == '\0') return;
823            if ((name[1] == '.') && (name[2] == '\0')) return;
824        }
825
826        ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
827        ci->next = *dirlist;
828        *dirlist = ci;
829    } else if (S_ISREG(mode) || S_ISLNK(mode)) {
830        copyinfo **filelist = args->filelist;
831
832        ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
833        ci->time = time;
834        ci->mode = mode;
835        ci->size = size;
836        ci->next = *filelist;
837        *filelist = ci;
838    } else {
839        fprintf(stderr, "skipping special file '%s'\n", name);
840    }
841}
842
843static int remote_build_list(int syncfd, copyinfo **filelist,
844                             const char *rpath, const char *lpath)
845{
846    copyinfo *dirlist = NULL;
847    sync_ls_build_list_cb_args args;
848
849    args.filelist = filelist;
850    args.dirlist = &dirlist;
851    args.rpath = rpath;
852    args.lpath = lpath;
853
854    /* Put the files/dirs in rpath on the lists. */
855    if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
856        return 1;
857    }
858
859    /* Recurse into each directory we found. */
860    while (dirlist != NULL) {
861        copyinfo *next = dirlist->next;
862        if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
863            return 1;
864        }
865        free(dirlist);
866        dirlist = next;
867    }
868
869    return 0;
870}
871
872static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
873{
874    struct utimbuf times = { time, time };
875    int r1 = utime(lpath, &times);
876
877    /* use umask for permissions */
878    mode_t mask=umask(0000);
879    umask(mask);
880    int r2 = chmod(lpath, mode & ~mask);
881
882    return r1 ? : r2;
883}
884
885/* Return a copy of the path string with / appended if needed */
886static char *add_slash_to_path(const char *path)
887{
888    if (path[strlen(path) - 1] != '/') {
889        size_t len = strlen(path) + 2;
890        char *path_with_slash = reinterpret_cast<char*>(malloc(len));
891        if (path_with_slash == NULL)
892            return NULL;
893        snprintf(path_with_slash, len, "%s/", path);
894        return path_with_slash;
895    } else {
896        return strdup(path);
897    }
898}
899
900static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
901                                 int copy_attrs)
902{
903    copyinfo *filelist = 0;
904    copyinfo *ci, *next;
905    int pulled = 0;
906    int skipped = 0;
907    char *rpath_clean = NULL;
908    char *lpath_clean = NULL;
909    int ret = 0;
910
911    if (rpath[0] == '\0' || lpath[0] == '\0') {
912        ret = -1;
913        goto finish;
914    }
915
916    /* Make sure that both directory paths end in a slash. */
917    rpath_clean = add_slash_to_path(rpath);
918    if (!rpath_clean) {
919        ret = -1;
920        goto finish;
921    }
922    lpath_clean = add_slash_to_path(lpath);
923    if (!lpath_clean) {
924        ret = -1;
925        goto finish;
926    }
927
928    /* Recursively build the list of files to copy. */
929    fprintf(stderr, "pull: building file list...\n");
930    if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
931        ret = -1;
932        goto finish;
933    }
934
935    for (ci = filelist; ci != 0; ci = next) {
936        next = ci->next;
937        if (ci->flag == 0) {
938            fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
939            if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
940                ret = -1;
941                goto finish;
942            }
943
944            if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
945                ret = -1;
946                goto finish;
947            }
948            pulled++;
949        } else {
950            skipped++;
951        }
952        free(ci);
953    }
954
955    fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
956            pulled, (pulled == 1) ? "" : "s",
957            skipped, (skipped == 1) ? "" : "s");
958
959finish:
960    free(lpath_clean);
961    free(rpath_clean);
962    return ret;
963}
964
965int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
966{
967    unsigned mode, time;
968    struct stat st;
969
970    int fd;
971
972    fd = adb_connect("sync:");
973    if(fd < 0) {
974        fprintf(stderr,"error: %s\n", adb_error());
975        return 1;
976    }
977
978    if(sync_readtime(fd, rpath, &time, &mode)) {
979        return 1;
980    }
981    if(mode == 0) {
982        fprintf(stderr,"remote object '%s' does not exist\n", rpath);
983        return 1;
984    }
985
986    if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
987        if(stat(lpath, &st) == 0) {
988            if(S_ISDIR(st.st_mode)) {
989                    /* if we're copying a remote file to a local directory,
990                    ** we *really* want to copy to localdir + "/" + remotefilename
991                    */
992                const char *name = adb_dirstop(rpath);
993                if(name == 0) {
994                    name = rpath;
995                } else {
996                    name++;
997                }
998                int  tmplen = strlen(name) + strlen(lpath) + 2;
999                char *tmp = reinterpret_cast<char*>(malloc(tmplen));
1000                if(tmp == 0) return 1;
1001                snprintf(tmp, tmplen, "%s/%s", lpath, name);
1002                lpath = tmp;
1003            }
1004        }
1005        BEGIN();
1006        if (sync_recv(fd, rpath, lpath, show_progress)) {
1007            return 1;
1008        } else {
1009            if (copy_attrs && set_time_and_mode(lpath, time, mode))
1010                return 1;
1011            END();
1012            sync_quit(fd);
1013            return 0;
1014        }
1015    } else if(S_ISDIR(mode)) {
1016        BEGIN();
1017        if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
1018            return 1;
1019        } else {
1020            END();
1021            sync_quit(fd);
1022            return 0;
1023        }
1024    } else {
1025        fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
1026        return 1;
1027    }
1028}
1029
1030int do_sync_sync(const char *lpath, const char *rpath, int listonly)
1031{
1032    fprintf(stderr,"syncing %s...\n",rpath);
1033
1034    int fd = adb_connect("sync:");
1035    if(fd < 0) {
1036        fprintf(stderr,"error: %s\n", adb_error());
1037        return 1;
1038    }
1039
1040    BEGIN();
1041    if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
1042        return 1;
1043    } else {
1044        END();
1045        sync_quit(fd);
1046        return 0;
1047    }
1048}
1049