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 
36 static unsigned long long total_bytes;
37 static long long start_time;
38 
NOW()39 static 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 
BEGIN()47 static void BEGIN()
48 {
49     total_bytes = 0;
50     start_time = NOW();
51 }
52 
END()53 static 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 
66 static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)";
67 
print_transfer_progress(unsigned long long bytes_current,unsigned long long bytes_total)68 static 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 
sync_quit(int fd)82 void 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 
92 typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
93 
sync_ls(int fd,const char * path,sync_ls_cb func,void * cookie)94 int 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 
128 fail:
129     adb_close(fd);
130     return -1;
131 }
132 
133 typedef struct syncsendbuf syncsendbuf;
134 
135 struct syncsendbuf {
136     unsigned id;
137     unsigned size;
138     char data[SYNC_DATA_MAX];
139 };
140 
141 static syncsendbuf send_buffer;
142 
sync_readtime(int fd,const char * path,unsigned int * timestamp,unsigned int * mode)143 int 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 
sync_start_readtime(int fd,const char * path)170 static 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 
sync_finish_readtime(int fd,unsigned int * timestamp,unsigned int * mode,unsigned int * size)186 static 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 
sync_readmode(int fd,const char * path,unsigned * mode)204 int 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 
write_data_file(int fd,const char * path,syncsendbuf * sbuf,int show_progress)229 static 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 
write_data_buffer(int fd,char * file_buffer,int size,syncsendbuf * sbuf,int show_progress)282 static 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
write_data_link(int fd,const char * path,syncsendbuf * sbuf)313 static 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 
sync_send(int fd,const char * lpath,const char * rpath,unsigned mtime,mode_t mode,int show_progress)337 static 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 
399 fail:
400     fprintf(stderr,"protocol failure\n");
401     adb_close(fd);
402     return -1;
403 }
404 
mkdirs(const char * name)405 static 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 
sync_recv(int fd,const char * rpath,const char * lpath,int show_progress)424 int 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 
518 remote_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 
do_sync_ls_cb(unsigned mode,unsigned size,unsigned time,const char * name,void * cookie)543 static 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 
do_sync_ls(const char * path)549 int 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 
565 typedef struct copyinfo copyinfo;
566 
567 struct 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 
mkcopyinfo(const char * spath,const char * dpath,const char * name,int isdir)579 copyinfo *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 
local_build_list(copyinfo ** filelist,const char * lpath,const char * rpath)609 static 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 
copy_local_dir_remote(int fd,const char * lpath,const char * rpath,int checktimestamps,int listonly)685 static 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 
do_sync_push(const char * lpath,const char * rpath,int show_progress)754 int 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 
814 typedef struct {
815     copyinfo **filelist;
816     copyinfo **dirlist;
817     const char *rpath;
818     const char *lpath;
819 } sync_ls_build_list_cb_args;
820 
821 void
sync_ls_build_list_cb(unsigned mode,unsigned size,unsigned time,const char * name,void * cookie)822 sync_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 
remote_build_list(int syncfd,copyinfo ** filelist,const char * rpath,const char * lpath)854 static 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 
set_time_and_mode(const char * lpath,unsigned int time,unsigned int mode)883 static 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 
copy_remote_dir_local(int fd,const char * rpath,const char * lpath,int copy_attrs)896 static 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 
do_sync_pull(const char * rpath,const char * lpath,int show_progress,int copy_attrs)952 int 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 
do_sync_sync(const char * lpath,const char * rpath,int listonly)1017 int 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