• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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     WriteFdExactly(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(!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 
128 fail:
129     adb_close(fd);
130     return -1;
131 }
132 
133 struct syncsendbuf {
134     unsigned id;
135     unsigned size;
136     char data[SYNC_DATA_MAX];
137 };
138 
139 static syncsendbuf send_buffer;
140 
sync_readtime(int fd,const char * path,unsigned int * timestamp,unsigned int * mode)141 int 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 
sync_start_readtime(int fd,const char * path)168 static 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 
sync_finish_readtime(int fd,unsigned int * timestamp,unsigned int * mode,unsigned int * size)184 static 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 
sync_readmode(int fd,const char * path,unsigned * mode)202 int 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 
write_data_file(int fd,const char * path,syncsendbuf * sbuf,int show_progress)227 static 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 
write_data_buffer(int fd,char * file_buffer,int size,syncsendbuf * sbuf,int show_progress)280 static 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)
311 extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
312 #else
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 = !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 
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(!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 
397 fail:
398     fprintf(stderr,"protocol failure\n");
399     adb_close(fd);
400     return -1;
401 }
402 
mkdirs(const char * name)403 static 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 
sync_recv(int fd,const char * rpath,const char * lpath,int show_progress)422 int 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 
516 remote_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 /* --- */
do_sync_ls_cb(unsigned mode,unsigned size,unsigned time,const char * name,void * cookie)536 static 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 
do_sync_ls(const char * path)542 int do_sync_ls(const char* path) {
543     std::string error;
544     int fd = adb_connect("sync:", &error);
545     if (fd < 0) {
546         fprintf(stderr,"error: %s\n", error.c_str());
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 
558 struct 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 
mkcopyinfo(const char * spath,const char * dpath,const char * name,int isdir)569 copyinfo *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 
local_build_list(copyinfo ** filelist,const char * lpath,const char * rpath)599 static 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 
copy_local_dir_remote(int fd,const char * lpath,const char * rpath,int checktimestamps,int listonly)673 static 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 
do_sync_push(const char * lpath,const char * rpath,int show_progress)742 int do_sync_push(const char *lpath, const char *rpath, int show_progress)
743 {
744     struct stat st;
745     unsigned mode;
746 
747     std::string error;
748     int fd = adb_connect("sync:", &error);
749     if (fd < 0) {
750         fprintf(stderr,"error: %s\n", error.c_str());
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 
803 struct sync_ls_build_list_cb_args {
804     copyinfo **filelist;
805     copyinfo **dirlist;
806     const char *rpath;
807     const char *lpath;
808 };
809 
810 void
sync_ls_build_list_cb(unsigned mode,unsigned size,unsigned time,const char * name,void * cookie)811 sync_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 
remote_build_list(int syncfd,copyinfo ** filelist,const char * rpath,const char * lpath)843 static 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 
set_time_and_mode(const char * lpath,time_t time,unsigned int mode)872 static 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 */
add_slash_to_path(const char * path)886 static 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 
copy_remote_dir_local(int fd,const char * rpath,const char * lpath,int copy_attrs)900 static 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 
959 finish:
960     free(lpath_clean);
961     free(rpath_clean);
962     return ret;
963 }
964 
do_sync_pull(const char * rpath,const char * lpath,int show_progress,int copy_attrs)965 int 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     std::string error;
971     int fd = adb_connect("sync:", &error);
972     if (fd < 0) {
973         fprintf(stderr,"error: %s\n", error.c_str());
974         return 1;
975     }
976 
977     if(sync_readtime(fd, rpath, &time, &mode)) {
978         return 1;
979     }
980     if(mode == 0) {
981         fprintf(stderr,"remote object '%s' does not exist\n", rpath);
982         return 1;
983     }
984 
985     if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
986         if(stat(lpath, &st) == 0) {
987             if(S_ISDIR(st.st_mode)) {
988                     /* if we're copying a remote file to a local directory,
989                     ** we *really* want to copy to localdir + "/" + remotefilename
990                     */
991                 const char *name = adb_dirstop(rpath);
992                 if(name == 0) {
993                     name = rpath;
994                 } else {
995                     name++;
996                 }
997                 int  tmplen = strlen(name) + strlen(lpath) + 2;
998                 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
999                 if(tmp == 0) return 1;
1000                 snprintf(tmp, tmplen, "%s/%s", lpath, name);
1001                 lpath = tmp;
1002             }
1003         }
1004         BEGIN();
1005         if (sync_recv(fd, rpath, lpath, show_progress)) {
1006             return 1;
1007         } else {
1008             if (copy_attrs && set_time_and_mode(lpath, time, mode))
1009                 return 1;
1010             END();
1011             sync_quit(fd);
1012             return 0;
1013         }
1014     } else if(S_ISDIR(mode)) {
1015         BEGIN();
1016         if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
1017             return 1;
1018         } else {
1019             END();
1020             sync_quit(fd);
1021             return 0;
1022         }
1023     } else {
1024         fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
1025         return 1;
1026     }
1027 }
1028 
do_sync_sync(const std::string & lpath,const std::string & rpath,bool list_only)1029 int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
1030 {
1031     fprintf(stderr, "syncing %s...\n", rpath.c_str());
1032 
1033     std::string error;
1034     int fd = adb_connect("sync:", &error);
1035     if (fd < 0) {
1036         fprintf(stderr, "error: %s\n", error.c_str());
1037         return 1;
1038     }
1039 
1040     BEGIN();
1041     if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
1042         return 1;
1043     } else {
1044         END();
1045         sync_quit(fd);
1046         return 0;
1047     }
1048 }
1049