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