blob: c1ab808550f9e789399cffb05f31b1567bcea439 [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,
Mark Lindner76f2a932014-03-11 17:55:59 -0700338 unsigned mtime, mode_t mode, int verifyApk, 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
353 if (verifyApk) {
354 int lfd;
355 zipfile_t zip;
356 zipentry_t entry;
357 int amt;
358
359 // if we are transferring an APK file, then sanity check to make sure
360 // we have a real zip file that contains an AndroidManifest.xml
361 // this requires that we read the entire file into memory.
362 lfd = adb_open(lpath, O_RDONLY);
363 if(lfd < 0) {
364 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
365 return -1;
366 }
367
368 size = adb_lseek(lfd, 0, SEEK_END);
369 if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) {
370 fprintf(stderr, "error seeking in file '%s'\n", lpath);
371 adb_close(lfd);
372 return 1;
373 }
374
375 file_buffer = (char *)malloc(size);
376 if (file_buffer == NULL) {
377 fprintf(stderr, "could not allocate buffer for '%s'\n",
378 lpath);
379 adb_close(lfd);
380 return 1;
381 }
382 amt = adb_read(lfd, file_buffer, size);
383 if (amt != size) {
384 fprintf(stderr, "error reading from file: '%s'\n", lpath);
385 adb_close(lfd);
386 free(file_buffer);
387 return 1;
388 }
389
390 adb_close(lfd);
391
392 zip = init_zipfile(file_buffer, size);
393 if (zip == NULL) {
394 fprintf(stderr, "file '%s' is not a valid zip file\n",
395 lpath);
396 free(file_buffer);
397 return 1;
398 }
399
400 entry = lookup_zipentry(zip, "AndroidManifest.xml");
401 release_zipfile(zip);
402 if (entry == NULL) {
403 fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
404 lpath);
405 free(file_buffer);
406 return 1;
407 }
408 }
409
410 msg.req.id = ID_SEND;
411 msg.req.namelen = htoll(len + r);
412
413 if(writex(fd, &msg.req, sizeof(msg.req)) ||
414 writex(fd, rpath, len) || writex(fd, tmp, r)) {
415 free(file_buffer);
416 goto fail;
417 }
418
419 if (file_buffer) {
Mark Lindner76f2a932014-03-11 17:55:59 -0700420 write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800421 free(file_buffer);
422 } else if (S_ISREG(mode))
Mark Lindner76f2a932014-03-11 17:55:59 -0700423 write_data_file(fd, lpath, sbuf, show_progress);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800424#ifdef HAVE_SYMLINKS
425 else if (S_ISLNK(mode))
426 write_data_link(fd, lpath, sbuf);
427#endif
428 else
429 goto fail;
430
431 msg.data.id = ID_DONE;
432 msg.data.size = htoll(mtime);
433 if(writex(fd, &msg.data, sizeof(msg.data)))
434 goto fail;
435
436 if(readx(fd, &msg.status, sizeof(msg.status)))
437 return -1;
438
439 if(msg.status.id != ID_OKAY) {
440 if(msg.status.id == ID_FAIL) {
441 len = ltohl(msg.status.msglen);
442 if(len > 256) len = 256;
443 if(readx(fd, sbuf->data, len)) {
444 return -1;
445 }
446 sbuf->data[len] = 0;
447 } else
448 strcpy(sbuf->data, "unknown reason");
449
450 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
451 return -1;
452 }
453
454 return 0;
455
456fail:
457 fprintf(stderr,"protocol failure\n");
458 adb_close(fd);
459 return -1;
460}
461
Mark Salyzyn60299df2014-04-30 09:10:31 -0700462static int mkdirs(const char *name)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800463{
464 int ret;
Mark Salyzyn60299df2014-04-30 09:10:31 -0700465 char *x = (char *)name + 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800466
467 for(;;) {
468 x = adb_dirstart(x);
469 if(x == 0) return 0;
470 *x = 0;
471 ret = adb_mkdir(name, 0775);
472 *x = OS_PATH_SEPARATOR;
473 if((ret < 0) && (errno != EEXIST)) {
474 return ret;
475 }
476 x++;
477 }
478 return 0;
479}
480
Mark Lindner76f2a932014-03-11 17:55:59 -0700481int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800482{
483 syncmsg msg;
484 int len;
485 int lfd = -1;
486 char *buffer = send_buffer.data;
487 unsigned id;
Mark Lindner76f2a932014-03-11 17:55:59 -0700488 unsigned long long size = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800489
490 len = strlen(rpath);
491 if(len > 1024) return -1;
492
Mark Lindner76f2a932014-03-11 17:55:59 -0700493 if (show_progress) {
494 // Determine remote file size.
495 syncmsg stat_msg;
496 stat_msg.req.id = ID_STAT;
497 stat_msg.req.namelen = htoll(len);
498
499 if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
500 writex(fd, rpath, len)) {
501 return -1;
502 }
503
504 if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
505 return -1;
506 }
507
508 if (stat_msg.stat.id != ID_STAT) return -1;
509
510 size = ltohl(stat_msg.stat.size);
511 }
512
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800513 msg.req.id = ID_RECV;
514 msg.req.namelen = htoll(len);
515 if(writex(fd, &msg.req, sizeof(msg.req)) ||
516 writex(fd, rpath, len)) {
517 return -1;
518 }
519
520 if(readx(fd, &msg.data, sizeof(msg.data))) {
521 return -1;
522 }
523 id = msg.data.id;
524
525 if((id == ID_DATA) || (id == ID_DONE)) {
526 adb_unlink(lpath);
Mark Salyzyn60299df2014-04-30 09:10:31 -0700527 mkdirs(lpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800528 lfd = adb_creat(lpath, 0644);
529 if(lfd < 0) {
530 fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
531 return -1;
532 }
533 goto handle_data;
534 } else {
535 goto remote_error;
536 }
537
538 for(;;) {
539 if(readx(fd, &msg.data, sizeof(msg.data))) {
540 return -1;
541 }
542 id = msg.data.id;
543
544 handle_data:
545 len = ltohl(msg.data.size);
546 if(id == ID_DONE) break;
547 if(id != ID_DATA) goto remote_error;
548 if(len > SYNC_DATA_MAX) {
549 fprintf(stderr,"data overrun\n");
550 adb_close(lfd);
551 return -1;
552 }
553
554 if(readx(fd, buffer, len)) {
555 adb_close(lfd);
556 return -1;
557 }
558
559 if(writex(lfd, buffer, len)) {
560 fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
561 adb_close(lfd);
562 return -1;
563 }
564
565 total_bytes += len;
Mark Lindner76f2a932014-03-11 17:55:59 -0700566
567 if (show_progress) {
568 print_transfer_progress(total_bytes, size);
569 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800570 }
571
572 adb_close(lfd);
573 return 0;
574
575remote_error:
576 adb_close(lfd);
577 adb_unlink(lpath);
578
579 if(id == ID_FAIL) {
580 len = ltohl(msg.data.size);
581 if(len > 256) len = 256;
582 if(readx(fd, buffer, len)) {
583 return -1;
584 }
585 buffer[len] = 0;
586 } else {
587 memcpy(buffer, &id, 4);
588 buffer[4] = 0;
589// strcpy(buffer,"unknown reason");
590 }
591 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
592 return 0;
593}
594
595
596
597/* --- */
598
599
600static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
601 const char *name, void *cookie)
602{
603 printf("%08x %08x %08x %s\n", mode, size, time, name);
604}
605
606int do_sync_ls(const char *path)
607{
608 int fd = adb_connect("sync:");
609 if(fd < 0) {
610 fprintf(stderr,"error: %s\n", adb_error());
611 return 1;
612 }
613
614 if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
615 return 1;
616 } else {
617 sync_quit(fd);
618 return 0;
619 }
620}
621
622typedef struct copyinfo copyinfo;
623
624struct copyinfo
625{
626 copyinfo *next;
627 const char *src;
628 const char *dst;
629 unsigned int time;
630 unsigned int mode;
631 unsigned int size;
632 int flag;
633 //char data[0];
634};
635
636copyinfo *mkcopyinfo(const char *spath, const char *dpath,
637 const char *name, int isdir)
638{
639 int slen = strlen(spath);
640 int dlen = strlen(dpath);
641 int nlen = strlen(name);
642 int ssize = slen + nlen + 2;
643 int dsize = dlen + nlen + 2;
644
645 copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize);
646 if(ci == 0) {
647 fprintf(stderr,"out of memory\n");
648 abort();
649 }
650
651 ci->next = 0;
652 ci->time = 0;
653 ci->mode = 0;
654 ci->size = 0;
655 ci->flag = 0;
656 ci->src = (const char*)(ci + 1);
657 ci->dst = ci->src + ssize;
658 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
659 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
660
661// fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst);
662 return ci;
663}
664
665
666static int local_build_list(copyinfo **filelist,
667 const char *lpath, const char *rpath)
668{
669 DIR *d;
670 struct dirent *de;
671 struct stat st;
672 copyinfo *dirlist = 0;
673 copyinfo *ci, *next;
674
675// fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath);
676
677 d = opendir(lpath);
678 if(d == 0) {
679 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
680 return -1;
681 }
682
683 while((de = readdir(d))) {
684 char stat_path[PATH_MAX];
685 char *name = de->d_name;
686
687 if(name[0] == '.') {
688 if(name[1] == 0) continue;
689 if((name[1] == '.') && (name[2] == 0)) continue;
690 }
691
692 /*
693 * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
694 * always returns DT_UNKNOWN, so we just use stat() for all cases.
695 */
696 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
697 continue;
698 strcpy(stat_path, lpath);
699 strcat(stat_path, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800700
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700701 if(!lstat(stat_path, &st)) {
702 if (S_ISDIR(st.st_mode)) {
703 ci = mkcopyinfo(lpath, rpath, name, 1);
704 ci->next = dirlist;
705 dirlist = ci;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800706 } else {
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700707 ci = mkcopyinfo(lpath, rpath, name, 0);
708 if(lstat(ci->src, &st)) {
709 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
710 free(ci);
711 closedir(d);
712 return -1;
713 }
714 if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
715 fprintf(stderr, "skipping special file '%s'\n", ci->src);
716 free(ci);
717 } else {
718 ci->time = st.st_mtime;
719 ci->mode = st.st_mode;
720 ci->size = st.st_size;
721 ci->next = *filelist;
722 *filelist = ci;
723 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800724 }
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700725 } else {
726 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800727 }
728 }
729
730 closedir(d);
731
732 for(ci = dirlist; ci != 0; ci = next) {
733 next = ci->next;
734 local_build_list(filelist, ci->src, ci->dst);
735 free(ci);
736 }
737
738 return 0;
739}
740
741
Anthony Newnam705c9442010-02-22 08:36:49 -0600742static 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 -0800743{
744 copyinfo *filelist = 0;
745 copyinfo *ci, *next;
746 int pushed = 0;
747 int skipped = 0;
748
749 if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
750 if(lpath[strlen(lpath) - 1] != '/') {
751 int tmplen = strlen(lpath)+2;
752 char *tmp = malloc(tmplen);
753 if(tmp == 0) return -1;
754 snprintf(tmp, tmplen, "%s/",lpath);
755 lpath = tmp;
756 }
757 if(rpath[strlen(rpath) - 1] != '/') {
758 int tmplen = strlen(rpath)+2;
759 char *tmp = malloc(tmplen);
760 if(tmp == 0) return -1;
761 snprintf(tmp, tmplen, "%s/",rpath);
762 rpath = tmp;
763 }
764
765 if(local_build_list(&filelist, lpath, rpath)) {
766 return -1;
767 }
768
769 if(checktimestamps){
770 for(ci = filelist; ci != 0; ci = ci->next) {
771 if(sync_start_readtime(fd, ci->dst)) {
772 return 1;
773 }
774 }
775 for(ci = filelist; ci != 0; ci = ci->next) {
776 unsigned int timestamp, mode, size;
777 if(sync_finish_readtime(fd, &timestamp, &mode, &size))
778 return 1;
779 if(size == ci->size) {
780 /* for links, we cannot update the atime/mtime */
781 if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
782 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
783 ci->flag = 1;
784 }
785 }
786 }
787 for(ci = filelist; ci != 0; ci = next) {
788 next = ci->next;
789 if(ci->flag == 0) {
Anthony Newnam705c9442010-02-22 08:36:49 -0600790 fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
791 if(!listonly &&
Mark Lindner76f2a932014-03-11 17:55:59 -0700792 sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */,
793 0 /* no show progress */)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800794 return 1;
795 }
796 pushed++;
797 } else {
798 skipped++;
799 }
800 free(ci);
801 }
802
803 fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
804 pushed, (pushed == 1) ? "" : "s",
805 skipped, (skipped == 1) ? "" : "s");
806
807 return 0;
808}
809
810
Mark Lindner76f2a932014-03-11 17:55:59 -0700811int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800812{
813 struct stat st;
814 unsigned mode;
815 int fd;
816
817 fd = adb_connect("sync:");
818 if(fd < 0) {
819 fprintf(stderr,"error: %s\n", adb_error());
820 return 1;
821 }
822
823 if(stat(lpath, &st)) {
824 fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
825 sync_quit(fd);
826 return 1;
827 }
828
829 if(S_ISDIR(st.st_mode)) {
830 BEGIN();
Anthony Newnam705c9442010-02-22 08:36:49 -0600831 if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800832 return 1;
833 } else {
834 END();
835 sync_quit(fd);
836 }
837 } else {
838 if(sync_readmode(fd, rpath, &mode)) {
839 return 1;
840 }
841 if((mode != 0) && S_ISDIR(mode)) {
842 /* if we're copying a local file to a remote directory,
843 ** we *really* want to copy to remotedir + "/" + localfilename
844 */
845 const char *name = adb_dirstop(lpath);
846 if(name == 0) {
847 name = lpath;
848 } else {
849 name++;
850 }
851 int tmplen = strlen(name) + strlen(rpath) + 2;
852 char *tmp = malloc(strlen(name) + strlen(rpath) + 2);
853 if(tmp == 0) return 1;
854 snprintf(tmp, tmplen, "%s/%s", rpath, name);
855 rpath = tmp;
856 }
857 BEGIN();
Mark Lindner76f2a932014-03-11 17:55:59 -0700858 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 -0800859 return 1;
860 } else {
861 END();
862 sync_quit(fd);
863 return 0;
864 }
865 }
866
867 return 0;
868}
869
870
871typedef struct {
872 copyinfo **filelist;
873 copyinfo **dirlist;
874 const char *rpath;
875 const char *lpath;
876} sync_ls_build_list_cb_args;
877
878void
879sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
880 const char *name, void *cookie)
881{
882 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
883 copyinfo *ci;
884
885 if (S_ISDIR(mode)) {
886 copyinfo **dirlist = args->dirlist;
887
888 /* Don't try recursing down "." or ".." */
889 if (name[0] == '.') {
890 if (name[1] == '\0') return;
891 if ((name[1] == '.') && (name[2] == '\0')) return;
892 }
893
894 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
895 ci->next = *dirlist;
896 *dirlist = ci;
897 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
898 copyinfo **filelist = args->filelist;
899
900 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
901 ci->time = time;
902 ci->mode = mode;
903 ci->size = size;
904 ci->next = *filelist;
905 *filelist = ci;
906 } else {
907 fprintf(stderr, "skipping special file '%s'\n", name);
908 }
909}
910
911static int remote_build_list(int syncfd, copyinfo **filelist,
912 const char *rpath, const char *lpath)
913{
914 copyinfo *dirlist = NULL;
915 sync_ls_build_list_cb_args args;
916
917 args.filelist = filelist;
918 args.dirlist = &dirlist;
919 args.rpath = rpath;
920 args.lpath = lpath;
921
922 /* Put the files/dirs in rpath on the lists. */
923 if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
924 return 1;
925 }
926
927 /* Recurse into each directory we found. */
928 while (dirlist != NULL) {
929 copyinfo *next = dirlist->next;
930 if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
931 return 1;
932 }
933 free(dirlist);
934 dirlist = next;
935 }
936
937 return 0;
938}
939
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700940static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
941{
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700942 struct utimbuf times = { time, time };
943 int r1 = utime(lpath, &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700944
945 /* use umask for permissions */
946 mode_t mask=umask(0000);
947 umask(mask);
948 int r2 = chmod(lpath, mode & ~mask);
949
950 return r1 ? : r2;
951}
952
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800953static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700954 int copy_attrs)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800955{
956 copyinfo *filelist = 0;
957 copyinfo *ci, *next;
958 int pulled = 0;
959 int skipped = 0;
960
961 /* Make sure that both directory paths end in a slash. */
962 if (rpath[0] == 0 || lpath[0] == 0) return -1;
963 if (rpath[strlen(rpath) - 1] != '/') {
964 int tmplen = strlen(rpath) + 2;
965 char *tmp = malloc(tmplen);
966 if (tmp == 0) return -1;
967 snprintf(tmp, tmplen, "%s/", rpath);
968 rpath = tmp;
969 }
970 if (lpath[strlen(lpath) - 1] != '/') {
971 int tmplen = strlen(lpath) + 2;
972 char *tmp = malloc(tmplen);
973 if (tmp == 0) return -1;
974 snprintf(tmp, tmplen, "%s/", lpath);
975 lpath = tmp;
976 }
977
978 fprintf(stderr, "pull: building file list...\n");
979 /* Recursively build the list of files to copy. */
980 if (remote_build_list(fd, &filelist, rpath, lpath)) {
981 return -1;
982 }
983
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800984 for (ci = filelist; ci != 0; ci = next) {
985 next = ci->next;
986 if (ci->flag == 0) {
987 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Mark Lindner76f2a932014-03-11 17:55:59 -0700988 if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800989 return 1;
990 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700991
992 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
993 return 1;
994 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800995 pulled++;
996 } else {
997 skipped++;
998 }
999 free(ci);
1000 }
1001
1002 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
1003 pulled, (pulled == 1) ? "" : "s",
1004 skipped, (skipped == 1) ? "" : "s");
1005
1006 return 0;
1007}
1008
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001009int 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 -08001010{
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001011 unsigned mode, time;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001012 struct stat st;
1013
1014 int fd;
1015
1016 fd = adb_connect("sync:");
1017 if(fd < 0) {
1018 fprintf(stderr,"error: %s\n", adb_error());
1019 return 1;
1020 }
1021
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001022 if(sync_readtime(fd, rpath, &time, &mode)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001023 return 1;
1024 }
1025 if(mode == 0) {
1026 fprintf(stderr,"remote object '%s' does not exist\n", rpath);
1027 return 1;
1028 }
1029
Matt Fischer457d81c2010-01-04 16:18:50 -06001030 if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001031 if(stat(lpath, &st) == 0) {
1032 if(S_ISDIR(st.st_mode)) {
1033 /* if we're copying a remote file to a local directory,
1034 ** we *really* want to copy to localdir + "/" + remotefilename
1035 */
1036 const char *name = adb_dirstop(rpath);
1037 if(name == 0) {
1038 name = rpath;
1039 } else {
1040 name++;
1041 }
1042 int tmplen = strlen(name) + strlen(lpath) + 2;
1043 char *tmp = malloc(tmplen);
1044 if(tmp == 0) return 1;
1045 snprintf(tmp, tmplen, "%s/%s", lpath, name);
1046 lpath = tmp;
1047 }
1048 }
1049 BEGIN();
Mark Lindner76f2a932014-03-11 17:55:59 -07001050 if (sync_recv(fd, rpath, lpath, show_progress)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001051 return 1;
1052 } else {
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001053 if (copy_attrs && set_time_and_mode(lpath, time, mode))
1054 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001055 END();
1056 sync_quit(fd);
1057 return 0;
1058 }
1059 } else if(S_ISDIR(mode)) {
1060 BEGIN();
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001061 if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001062 return 1;
1063 } else {
1064 END();
1065 sync_quit(fd);
1066 return 0;
1067 }
1068 } else {
1069 fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
1070 return 1;
1071 }
1072}
1073
Anthony Newnam705c9442010-02-22 08:36:49 -06001074int do_sync_sync(const char *lpath, const char *rpath, int listonly)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001075{
1076 fprintf(stderr,"syncing %s...\n",rpath);
1077
1078 int fd = adb_connect("sync:");
1079 if(fd < 0) {
1080 fprintf(stderr,"error: %s\n", adb_error());
1081 return 1;
1082 }
1083
1084 BEGIN();
Anthony Newnam705c9442010-02-22 08:36:49 -06001085 if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001086 return 1;
1087 } else {
1088 END();
1089 sync_quit(fd);
1090 return 0;
1091 }
1092}