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