blob: ad59e817d06ef04ef9240f44333a1cf9122458cf [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>
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -070028#include <utime.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080029
30#include "sysdeps.h"
31#include "adb.h"
32#include "adb_client.h"
33#include "file_sync_service.h"
34
35
Jeff Smithd9a14302013-06-15 15:32:05 -050036static unsigned long long total_bytes;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080037static long long start_time;
38
39static long long NOW()
40{
41 struct timeval tv;
42 gettimeofday(&tv, 0);
43 return ((long long) tv.tv_usec) +
44 1000000LL * ((long long) tv.tv_sec);
45}
46
47static void BEGIN()
48{
49 total_bytes = 0;
50 start_time = NOW();
51}
52
53static void END()
54{
55 long long t = NOW() - start_time;
56 if(total_bytes == 0) return;
57
58 if (t == 0) /* prevent division by 0 :-) */
59 t = 1000000;
60
Mike Lockwoodee878752010-12-14 23:07:32 -080061 fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
Jeff Smithd9a14302013-06-15 15:32:05 -050062 ((total_bytes * 1000000LL) / t) / 1024LL,
63 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080064}
65
Mark Lindner76f2a932014-03-11 17:55:59 -070066static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)";
67
68static void print_transfer_progress(unsigned long long bytes_current,
69 unsigned long long bytes_total) {
70 if (bytes_total == 0) return;
71
72 fprintf(stderr, transfer_progress_format, bytes_current, bytes_total,
73 (int) (bytes_current * 100 / bytes_total));
74
75 if (bytes_current == bytes_total) {
76 fputc('\n', stderr);
77 }
78
79 fflush(stderr);
80}
81
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080082void 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
92typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
93
94int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
95{
96 syncmsg msg;
97 char buf[257];
98 int len;
99
100 len = strlen(path);
101 if(len > 1024) goto fail;
102
103 msg.req.id = ID_LIST;
104 msg.req.namelen = htoll(len);
105
106 if(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
128fail:
129 adb_close(fd);
130 return -1;
131}
132
133typedef struct syncsendbuf syncsendbuf;
134
135struct syncsendbuf {
136 unsigned id;
137 unsigned size;
138 char data[SYNC_DATA_MAX];
139};
140
141static syncsendbuf send_buffer;
142
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700143int sync_readtime(int fd, const char *path, unsigned int *timestamp,
144 unsigned int *mode)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800145{
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);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700166 *mode = ltohl(msg.stat.mode);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800167 return 0;
168}
169
170static 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
186static int sync_finish_readtime(int fd, unsigned int *timestamp,
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200187 unsigned int *mode, unsigned int *size)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800188{
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
204int 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
Mark Lindner76f2a932014-03-11 17:55:59 -0700229static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800230{
231 int lfd, err = 0;
Mark Lindner76f2a932014-03-11 17:55:59 -0700232 unsigned long long size = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800233
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
Mark Lindner76f2a932014-03-11 17:55:59 -0700240 if (show_progress) {
241 // Determine local file size.
242 struct stat st;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700243 if (fstat(lfd, &st)) {
Mark Lindner76f2a932014-03-11 17:55:59 -0700244 fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
245 return -1;
246 }
247
248 size = st.st_size;
249 }
250
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800251 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;
Mark Lindner76f2a932014-03-11 17:55:59 -0700272
273 if (show_progress) {
274 print_transfer_progress(total_bytes, size);
275 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800276 }
277
278 adb_close(lfd);
279 return err;
280}
281
Mark Lindner76f2a932014-03-11 17:55:59 -0700282static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
283 int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800284{
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;
Mark Lindner76f2a932014-03-11 17:55:59 -0700303
304 if (show_progress) {
305 print_transfer_progress(total, size);
306 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800307 }
308
309 return err;
310}
311
312#ifdef HAVE_SYMLINKS
313static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
314{
315 int len, ret;
316
317 len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
318 if(len < 0) {
319 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
320 return -1;
321 }
322 sbuf->data[len] = '\0';
323
324 sbuf->size = htoll(len + 1);
325 sbuf->id = ID_DATA;
326
327 ret = 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
337static int sync_send(int fd, const char *lpath, const char *rpath,
Jeff Sharkey960df972014-06-09 17:30:57 -0700338 unsigned mtime, mode_t mode, int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800339{
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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800353 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) {
Mark Lindner76f2a932014-03-11 17:55:59 -0700363 write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800364 free(file_buffer);
365 } else if (S_ISREG(mode))
Mark Lindner76f2a932014-03-11 17:55:59 -0700366 write_data_file(fd, lpath, sbuf, show_progress);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800367#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
399fail:
400 fprintf(stderr,"protocol failure\n");
401 adb_close(fd);
402 return -1;
403}
404
Mark Salyzyn60299df2014-04-30 09:10:31 -0700405static int mkdirs(const char *name)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800406{
407 int ret;
Mark Salyzyn60299df2014-04-30 09:10:31 -0700408 char *x = (char *)name + 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800409
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
Mark Lindner76f2a932014-03-11 17:55:59 -0700424int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800425{
426 syncmsg msg;
427 int len;
428 int lfd = -1;
429 char *buffer = send_buffer.data;
430 unsigned id;
Mark Lindner76f2a932014-03-11 17:55:59 -0700431 unsigned long long size = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800432
433 len = strlen(rpath);
434 if(len > 1024) return -1;
435
Mark Lindner76f2a932014-03-11 17:55:59 -0700436 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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800456 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);
Mark Salyzyn60299df2014-04-30 09:10:31 -0700470 mkdirs(lpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800471 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;
Mark Lindner76f2a932014-03-11 17:55:59 -0700509
510 if (show_progress) {
511 print_transfer_progress(total_bytes, size);
512 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800513 }
514
515 adb_close(lfd);
516 return 0;
517
518remote_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
543static 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
549int 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
565typedef struct copyinfo copyinfo;
566
567struct 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
579copyinfo *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
609static 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);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800643
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700644 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;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800649 } else {
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700650 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 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800667 }
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700668 } else {
669 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800670 }
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
Anthony Newnam705c9442010-02-22 08:36:49 -0600685static 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 -0800686{
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) {
Anthony Newnam705c9442010-02-22 08:36:49 -0600733 fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
734 if(!listonly &&
Jeff Sharkey960df972014-06-09 17:30:57 -0700735 sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
Mark Lindner76f2a932014-03-11 17:55:59 -0700736 0 /* no show progress */)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800737 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
Jeff Sharkey960df972014-06-09 17:30:57 -0700754int do_sync_push(const char *lpath, const char *rpath, int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800755{
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();
Anthony Newnam705c9442010-02-22 08:36:49 -0600774 if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800775 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();
Jeff Sharkey960df972014-06-09 17:30:57 -0700801 if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800802 return 1;
803 } else {
804 END();
805 sync_quit(fd);
806 return 0;
807 }
808 }
809
810 return 0;
811}
812
813
814typedef struct {
815 copyinfo **filelist;
816 copyinfo **dirlist;
817 const char *rpath;
818 const char *lpath;
819} sync_ls_build_list_cb_args;
820
821void
822sync_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
854static 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
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700883static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
884{
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700885 struct utimbuf times = { time, time };
886 int r1 = utime(lpath, &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700887
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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800896static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700897 int copy_attrs)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800898{
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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800927 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);
Mark Lindner76f2a932014-03-11 17:55:59 -0700931 if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800932 return 1;
933 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700934
935 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
936 return 1;
937 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800938 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
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700952int 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 -0800953{
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700954 unsigned mode, time;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800955 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
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700965 if(sync_readtime(fd, rpath, &time, &mode)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800966 return 1;
967 }
968 if(mode == 0) {
969 fprintf(stderr,"remote object '%s' does not exist\n", rpath);
970 return 1;
971 }
972
Matt Fischer457d81c2010-01-04 16:18:50 -0600973 if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800974 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();
Mark Lindner76f2a932014-03-11 17:55:59 -0700993 if (sync_recv(fd, rpath, lpath, show_progress)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800994 return 1;
995 } else {
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700996 if (copy_attrs && set_time_and_mode(lpath, time, mode))
997 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800998 END();
999 sync_quit(fd);
1000 return 0;
1001 }
1002 } else if(S_ISDIR(mode)) {
1003 BEGIN();
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001004 if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001005 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
Anthony Newnam705c9442010-02-22 08:36:49 -06001017int do_sync_sync(const char *lpath, const char *rpath, int listonly)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001018{
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();
Anthony Newnam705c9442010-02-22 08:36:49 -06001028 if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001029 return 1;
1030 } else {
1031 END();
1032 sync_quit(fd);
1033 return 0;
1034 }
1035}