blob: 2efc890e82d766d934e13ff6ead957948ad1e6aa [file] [log] [blame]
The Android Open Source Project9ca14dc2009-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
Dan Albertb302d122015-02-24 15:51:19 -080017#include <dirent.h>
18#include <errno.h>
19#include <limits.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080020#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080023#include <sys/stat.h>
24#include <sys/time.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080025#include <sys/types.h>
Dan Albertb302d122015-02-24 15:51:19 -080026#include <time.h>
Greg Hackmann8b689142014-05-06 08:48:18 -070027#include <utime.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080028
29#include "sysdeps.h"
Dan Albertb302d122015-02-24 15:51:19 -080030
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080031#include "adb.h"
32#include "adb_client.h"
Dan Albert66a91b02015-02-24 21:26:58 -080033#include "adb_io.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080034#include "file_sync_service.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080035
Jeff Smith51d3fc12013-06-15 15:32:05 -050036static unsigned long long total_bytes;
The Android Open Source Project9ca14dc2009-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 Lockwoodeaf5a1e2010-12-14 23:07:32 -080061 fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
Jeff Smith51d3fc12013-06-15 15:32:05 -050062 ((total_bytes * 1000000LL) / t) / 1024LL,
63 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080064}
65
Mark Lindner9f9d1452014-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
Elliott Hughes712416a2015-05-05 18:26:10 -070082static void sync_quit(int fd) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080083 syncmsg msg;
84
85 msg.req.id = ID_QUIT;
86 msg.req.namelen = 0;
87
Dan Albert66a91b02015-02-24 21:26:58 -080088 WriteFdExactly(fd, &msg.req, sizeof(msg.req));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080089}
90
91typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
92
Elliott Hughes712416a2015-05-05 18:26:10 -070093static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080094 syncmsg msg;
95 char buf[257];
96 int len;
97
98 len = strlen(path);
99 if(len > 1024) goto fail;
100
101 msg.req.id = ID_LIST;
102 msg.req.namelen = htoll(len);
103
Dan Albert66a91b02015-02-24 21:26:58 -0800104 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
105 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800106 goto fail;
107 }
108
109 for(;;) {
Dan Albert66a91b02015-02-24 21:26:58 -0800110 if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800111 if(msg.dent.id == ID_DONE) return 0;
112 if(msg.dent.id != ID_DENT) break;
113
114 len = ltohl(msg.dent.namelen);
115 if(len > 256) break;
116
Dan Albert66a91b02015-02-24 21:26:58 -0800117 if(!ReadFdExactly(fd, buf, len)) break;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800118 buf[len] = 0;
119
120 func(ltohl(msg.dent.mode),
121 ltohl(msg.dent.size),
122 ltohl(msg.dent.time),
123 buf, cookie);
124 }
125
126fail:
127 adb_close(fd);
128 return -1;
129}
130
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800131struct syncsendbuf {
132 unsigned id;
133 unsigned size;
134 char data[SYNC_DATA_MAX];
135};
136
137static syncsendbuf send_buffer;
138
Elliott Hughes712416a2015-05-05 18:26:10 -0700139static int sync_readtime(int fd, const char* path, unsigned int* timestamp, unsigned int* mode) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800140 syncmsg msg;
141 int len = strlen(path);
142
143 msg.req.id = ID_STAT;
144 msg.req.namelen = htoll(len);
145
Dan Albert66a91b02015-02-24 21:26:58 -0800146 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
147 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800148 return -1;
149 }
150
Dan Albert66a91b02015-02-24 21:26:58 -0800151 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800152 return -1;
153 }
154
155 if(msg.stat.id != ID_STAT) {
156 return -1;
157 }
158
159 *timestamp = ltohl(msg.stat.time);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700160 *mode = ltohl(msg.stat.mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800161 return 0;
162}
163
164static int sync_start_readtime(int fd, const char *path)
165{
166 syncmsg msg;
167 int len = strlen(path);
168
169 msg.req.id = ID_STAT;
170 msg.req.namelen = htoll(len);
171
Dan Albert66a91b02015-02-24 21:26:58 -0800172 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
173 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800174 return -1;
175 }
176
177 return 0;
178}
179
180static int sync_finish_readtime(int fd, unsigned int *timestamp,
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200181 unsigned int *mode, unsigned int *size)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800182{
183 syncmsg msg;
184
Dan Albert66a91b02015-02-24 21:26:58 -0800185 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800186 return -1;
187
188 if(msg.stat.id != ID_STAT)
189 return -1;
190
191 *timestamp = ltohl(msg.stat.time);
192 *mode = ltohl(msg.stat.mode);
193 *size = ltohl(msg.stat.size);
194
195 return 0;
196}
197
Elliott Hughes712416a2015-05-05 18:26:10 -0700198static int sync_readmode(int fd, const char* path, unsigned* mode) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800199 syncmsg msg;
200 int len = strlen(path);
201
202 msg.req.id = ID_STAT;
203 msg.req.namelen = htoll(len);
204
Dan Albert66a91b02015-02-24 21:26:58 -0800205 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
206 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800207 return -1;
208 }
209
Dan Albert66a91b02015-02-24 21:26:58 -0800210 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800211 return -1;
212 }
213
214 if(msg.stat.id != ID_STAT) {
215 return -1;
216 }
217
218 *mode = ltohl(msg.stat.mode);
219 return 0;
220}
221
Mark Lindner9f9d1452014-03-11 17:55:59 -0700222static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800223{
224 int lfd, err = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700225 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800226
227 lfd = adb_open(path, O_RDONLY);
228 if(lfd < 0) {
229 fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
230 return -1;
231 }
232
Mark Lindner9f9d1452014-03-11 17:55:59 -0700233 if (show_progress) {
234 // Determine local file size.
235 struct stat st;
eric.yan466d3f42015-02-03 22:16:29 +0800236 if (stat(path, &st)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700237 fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
238 return -1;
239 }
240
241 size = st.st_size;
242 }
243
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800244 sbuf->id = ID_DATA;
245 for(;;) {
246 int ret;
247
248 ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
249 if(!ret)
250 break;
251
252 if(ret < 0) {
253 if(errno == EINTR)
254 continue;
255 fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
256 break;
257 }
258
259 sbuf->size = htoll(ret);
Dan Albert66a91b02015-02-24 21:26:58 -0800260 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800261 err = -1;
262 break;
263 }
264 total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700265
266 if (show_progress) {
267 print_transfer_progress(total_bytes, size);
268 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800269 }
270
271 adb_close(lfd);
272 return err;
273}
274
Mark Lindner9f9d1452014-03-11 17:55:59 -0700275static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
276 int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800277{
278 int err = 0;
279 int total = 0;
280
281 sbuf->id = ID_DATA;
282 while (total < size) {
283 int count = size - total;
284 if (count > SYNC_DATA_MAX) {
285 count = SYNC_DATA_MAX;
286 }
287
288 memcpy(sbuf->data, &file_buffer[total], count);
289 sbuf->size = htoll(count);
Dan Albert66a91b02015-02-24 21:26:58 -0800290 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800291 err = -1;
292 break;
293 }
294 total += count;
295 total_bytes += count;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700296
297 if (show_progress) {
298 print_transfer_progress(total, size);
299 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800300 }
301
302 return err;
303}
304
Elliott Hughes944e1d72015-01-12 14:26:36 -0800305#if defined(_WIN32)
306extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
307#else
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800308static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
309{
310 int len, ret;
311
312 len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
313 if(len < 0) {
314 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
315 return -1;
316 }
317 sbuf->data[len] = '\0';
318
319 sbuf->size = htoll(len + 1);
320 sbuf->id = ID_DATA;
321
Dan Albert66a91b02015-02-24 21:26:58 -0800322 ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800323 if(ret)
324 return -1;
325
326 total_bytes += len + 1;
327
328 return 0;
329}
330#endif
331
332static int sync_send(int fd, const char *lpath, const char *rpath,
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700333 unsigned mtime, mode_t mode, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800334{
335 syncmsg msg;
336 int len, r;
337 syncsendbuf *sbuf = &send_buffer;
338 char* file_buffer = NULL;
339 int size = 0;
340 char tmp[64];
341
342 len = strlen(rpath);
343 if(len > 1024) goto fail;
344
345 snprintf(tmp, sizeof(tmp), ",%d", mode);
346 r = strlen(tmp);
347
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800348 msg.req.id = ID_SEND;
349 msg.req.namelen = htoll(len + r);
350
Dan Albert66a91b02015-02-24 21:26:58 -0800351 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
352 !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800353 free(file_buffer);
354 goto fail;
355 }
356
357 if (file_buffer) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700358 write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800359 free(file_buffer);
360 } else if (S_ISREG(mode))
Mark Lindner9f9d1452014-03-11 17:55:59 -0700361 write_data_file(fd, lpath, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800362 else if (S_ISLNK(mode))
363 write_data_link(fd, lpath, sbuf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800364 else
365 goto fail;
366
367 msg.data.id = ID_DONE;
368 msg.data.size = htoll(mtime);
Dan Albert66a91b02015-02-24 21:26:58 -0800369 if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800370 goto fail;
371
Dan Albert66a91b02015-02-24 21:26:58 -0800372 if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800373 return -1;
374
375 if(msg.status.id != ID_OKAY) {
376 if(msg.status.id == ID_FAIL) {
377 len = ltohl(msg.status.msglen);
378 if(len > 256) len = 256;
Dan Albert66a91b02015-02-24 21:26:58 -0800379 if(!ReadFdExactly(fd, sbuf->data, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800380 return -1;
381 }
382 sbuf->data[len] = 0;
383 } else
384 strcpy(sbuf->data, "unknown reason");
385
386 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
387 return -1;
388 }
389
390 return 0;
391
392fail:
393 fprintf(stderr,"protocol failure\n");
394 adb_close(fd);
395 return -1;
396}
397
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700398static int mkdirs(const char *name)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800399{
400 int ret;
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700401 char *x = (char *)name + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800402
403 for(;;) {
404 x = adb_dirstart(x);
405 if(x == 0) return 0;
406 *x = 0;
407 ret = adb_mkdir(name, 0775);
408 *x = OS_PATH_SEPARATOR;
409 if((ret < 0) && (errno != EEXIST)) {
410 return ret;
411 }
412 x++;
413 }
414 return 0;
415}
416
Elliott Hughes712416a2015-05-05 18:26:10 -0700417static int sync_recv(int fd, const char* rpath, const char* lpath, int show_progress) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800418 syncmsg msg;
419 int len;
420 int lfd = -1;
421 char *buffer = send_buffer.data;
422 unsigned id;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700423 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800424
425 len = strlen(rpath);
426 if(len > 1024) return -1;
427
Mark Lindner9f9d1452014-03-11 17:55:59 -0700428 if (show_progress) {
429 // Determine remote file size.
430 syncmsg stat_msg;
431 stat_msg.req.id = ID_STAT;
432 stat_msg.req.namelen = htoll(len);
433
Dan Albert66a91b02015-02-24 21:26:58 -0800434 if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
435 !WriteFdExactly(fd, rpath, len)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700436 return -1;
437 }
438
Dan Albert66a91b02015-02-24 21:26:58 -0800439 if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700440 return -1;
441 }
442
443 if (stat_msg.stat.id != ID_STAT) return -1;
444
445 size = ltohl(stat_msg.stat.size);
446 }
447
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800448 msg.req.id = ID_RECV;
449 msg.req.namelen = htoll(len);
Dan Albert66a91b02015-02-24 21:26:58 -0800450 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
451 !WriteFdExactly(fd, rpath, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800452 return -1;
453 }
454
Dan Albert66a91b02015-02-24 21:26:58 -0800455 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800456 return -1;
457 }
458 id = msg.data.id;
459
460 if((id == ID_DATA) || (id == ID_DONE)) {
461 adb_unlink(lpath);
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700462 mkdirs(lpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800463 lfd = adb_creat(lpath, 0644);
464 if(lfd < 0) {
465 fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
466 return -1;
467 }
468 goto handle_data;
469 } else {
470 goto remote_error;
471 }
472
473 for(;;) {
Dan Albert66a91b02015-02-24 21:26:58 -0800474 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800475 return -1;
476 }
477 id = msg.data.id;
478
479 handle_data:
480 len = ltohl(msg.data.size);
481 if(id == ID_DONE) break;
482 if(id != ID_DATA) goto remote_error;
483 if(len > SYNC_DATA_MAX) {
484 fprintf(stderr,"data overrun\n");
485 adb_close(lfd);
486 return -1;
487 }
488
Dan Albert66a91b02015-02-24 21:26:58 -0800489 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800490 adb_close(lfd);
491 return -1;
492 }
493
Dan Albert66a91b02015-02-24 21:26:58 -0800494 if(!WriteFdExactly(lfd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800495 fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
496 adb_close(lfd);
497 return -1;
498 }
499
500 total_bytes += len;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700501
502 if (show_progress) {
503 print_transfer_progress(total_bytes, size);
504 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800505 }
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;
Dan Albert66a91b02015-02-24 21:26:58 -0800517 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800518 return -1;
519 }
520 buffer[len] = 0;
521 } else {
522 memcpy(buffer, &id, 4);
523 buffer[4] = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800524 }
525 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
526 return 0;
527}
528
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800529/* --- */
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800530static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
531 const char *name, void *cookie)
532{
533 printf("%08x %08x %08x %s\n", mode, size, time, name);
534}
535
Elliott Hughes04a98c22015-04-29 08:35:59 -0700536int do_sync_ls(const char* path) {
537 std::string error;
538 int fd = adb_connect("sync:", &error);
539 if (fd < 0) {
540 fprintf(stderr,"error: %s\n", error.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800541 return 1;
542 }
543
544 if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
545 return 1;
546 } else {
547 sync_quit(fd);
548 return 0;
549 }
550}
551
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800552struct copyinfo
553{
554 copyinfo *next;
555 const char *src;
556 const char *dst;
557 unsigned int time;
558 unsigned int mode;
559 unsigned int size;
560 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800561};
562
Elliott Hughes712416a2015-05-05 18:26:10 -0700563static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800564 int slen = strlen(spath);
565 int dlen = strlen(dpath);
566 int nlen = strlen(name);
567 int ssize = slen + nlen + 2;
568 int dsize = dlen + nlen + 2;
569
Elliott Hughes712416a2015-05-05 18:26:10 -0700570 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800571 if(ci == 0) {
572 fprintf(stderr,"out of memory\n");
573 abort();
574 }
575
576 ci->next = 0;
577 ci->time = 0;
578 ci->mode = 0;
579 ci->size = 0;
580 ci->flag = 0;
581 ci->src = (const char*)(ci + 1);
582 ci->dst = ci->src + ssize;
583 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
584 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
585
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800586 return ci;
587}
588
589
590static int local_build_list(copyinfo **filelist,
591 const char *lpath, const char *rpath)
592{
593 DIR *d;
594 struct dirent *de;
595 struct stat st;
596 copyinfo *dirlist = 0;
597 copyinfo *ci, *next;
598
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800599 d = opendir(lpath);
600 if(d == 0) {
601 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
602 return -1;
603 }
604
605 while((de = readdir(d))) {
606 char stat_path[PATH_MAX];
607 char *name = de->d_name;
608
609 if(name[0] == '.') {
610 if(name[1] == 0) continue;
611 if((name[1] == '.') && (name[2] == 0)) continue;
612 }
613
614 /*
615 * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
616 * always returns DT_UNKNOWN, so we just use stat() for all cases.
617 */
618 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
619 continue;
620 strcpy(stat_path, lpath);
621 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800622
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700623 if(!lstat(stat_path, &st)) {
624 if (S_ISDIR(st.st_mode)) {
625 ci = mkcopyinfo(lpath, rpath, name, 1);
626 ci->next = dirlist;
627 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800628 } else {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700629 ci = mkcopyinfo(lpath, rpath, name, 0);
630 if(lstat(ci->src, &st)) {
631 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
632 free(ci);
633 closedir(d);
634 return -1;
635 }
636 if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
637 fprintf(stderr, "skipping special file '%s'\n", ci->src);
638 free(ci);
639 } else {
640 ci->time = st.st_mtime;
641 ci->mode = st.st_mode;
642 ci->size = st.st_size;
643 ci->next = *filelist;
644 *filelist = ci;
645 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800646 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700647 } else {
648 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800649 }
650 }
651
652 closedir(d);
653
654 for(ci = dirlist; ci != 0; ci = next) {
655 next = ci->next;
656 local_build_list(filelist, ci->src, ci->dst);
657 free(ci);
658 }
659
660 return 0;
661}
662
663
Anthony Newnamdd2db142010-02-22 08:36:49 -0600664static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800665{
666 copyinfo *filelist = 0;
667 copyinfo *ci, *next;
668 int pushed = 0;
669 int skipped = 0;
670
671 if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
672 if(lpath[strlen(lpath) - 1] != '/') {
673 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800674 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800675 if(tmp == 0) return -1;
676 snprintf(tmp, tmplen, "%s/",lpath);
677 lpath = tmp;
678 }
679 if(rpath[strlen(rpath) - 1] != '/') {
680 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800681 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800682 if(tmp == 0) return -1;
683 snprintf(tmp, tmplen, "%s/",rpath);
684 rpath = tmp;
685 }
686
687 if(local_build_list(&filelist, lpath, rpath)) {
688 return -1;
689 }
690
691 if(checktimestamps){
692 for(ci = filelist; ci != 0; ci = ci->next) {
693 if(sync_start_readtime(fd, ci->dst)) {
694 return 1;
695 }
696 }
697 for(ci = filelist; ci != 0; ci = ci->next) {
698 unsigned int timestamp, mode, size;
699 if(sync_finish_readtime(fd, &timestamp, &mode, &size))
700 return 1;
701 if(size == ci->size) {
702 /* for links, we cannot update the atime/mtime */
703 if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
704 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
705 ci->flag = 1;
706 }
707 }
708 }
709 for(ci = filelist; ci != 0; ci = next) {
710 next = ci->next;
711 if(ci->flag == 0) {
Anthony Newnamdd2db142010-02-22 08:36:49 -0600712 fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
713 if(!listonly &&
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700714 sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
Mark Lindner9f9d1452014-03-11 17:55:59 -0700715 0 /* no show progress */)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800716 return 1;
717 }
718 pushed++;
719 } else {
720 skipped++;
721 }
722 free(ci);
723 }
724
725 fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
726 pushed, (pushed == 1) ? "" : "s",
727 skipped, (skipped == 1) ? "" : "s");
728
729 return 0;
730}
731
732
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700733int do_sync_push(const char *lpath, const char *rpath, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800734{
735 struct stat st;
736 unsigned mode;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800737
Elliott Hughes04a98c22015-04-29 08:35:59 -0700738 std::string error;
739 int fd = adb_connect("sync:", &error);
740 if (fd < 0) {
741 fprintf(stderr,"error: %s\n", error.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800742 return 1;
743 }
744
745 if(stat(lpath, &st)) {
746 fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
747 sync_quit(fd);
748 return 1;
749 }
750
751 if(S_ISDIR(st.st_mode)) {
752 BEGIN();
Anthony Newnamdd2db142010-02-22 08:36:49 -0600753 if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800754 return 1;
755 } else {
756 END();
757 sync_quit(fd);
758 }
759 } else {
760 if(sync_readmode(fd, rpath, &mode)) {
761 return 1;
762 }
763 if((mode != 0) && S_ISDIR(mode)) {
764 /* if we're copying a local file to a remote directory,
765 ** we *really* want to copy to remotedir + "/" + localfilename
766 */
767 const char *name = adb_dirstop(lpath);
768 if(name == 0) {
769 name = lpath;
770 } else {
771 name++;
772 }
773 int tmplen = strlen(name) + strlen(rpath) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800774 char *tmp = reinterpret_cast<char*>(
775 malloc(strlen(name) + strlen(rpath) + 2));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800776 if(tmp == 0) return 1;
777 snprintf(tmp, tmplen, "%s/%s", rpath, name);
778 rpath = tmp;
779 }
780 BEGIN();
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700781 if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800782 return 1;
783 } else {
784 END();
785 sync_quit(fd);
786 return 0;
787 }
788 }
789
790 return 0;
791}
792
793
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700794struct sync_ls_build_list_cb_args {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800795 copyinfo **filelist;
796 copyinfo **dirlist;
797 const char *rpath;
798 const char *lpath;
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700799};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800800
Elliott Hughes712416a2015-05-05 18:26:10 -0700801static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
802 const char* name, void* cookie)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800803{
804 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
805 copyinfo *ci;
806
807 if (S_ISDIR(mode)) {
808 copyinfo **dirlist = args->dirlist;
809
810 /* Don't try recursing down "." or ".." */
811 if (name[0] == '.') {
812 if (name[1] == '\0') return;
813 if ((name[1] == '.') && (name[2] == '\0')) return;
814 }
815
816 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
817 ci->next = *dirlist;
818 *dirlist = ci;
819 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
820 copyinfo **filelist = args->filelist;
821
822 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
823 ci->time = time;
824 ci->mode = mode;
825 ci->size = size;
826 ci->next = *filelist;
827 *filelist = ci;
828 } else {
829 fprintf(stderr, "skipping special file '%s'\n", name);
830 }
831}
832
833static int remote_build_list(int syncfd, copyinfo **filelist,
834 const char *rpath, const char *lpath)
835{
836 copyinfo *dirlist = NULL;
837 sync_ls_build_list_cb_args args;
838
839 args.filelist = filelist;
840 args.dirlist = &dirlist;
841 args.rpath = rpath;
842 args.lpath = lpath;
843
844 /* Put the files/dirs in rpath on the lists. */
845 if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
846 return 1;
847 }
848
849 /* Recurse into each directory we found. */
850 while (dirlist != NULL) {
851 copyinfo *next = dirlist->next;
852 if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
853 return 1;
854 }
855 free(dirlist);
856 dirlist = next;
857 }
858
859 return 0;
860}
861
Dan Albertf30d73c2015-02-25 17:51:28 -0800862static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700863{
Greg Hackmann8b689142014-05-06 08:48:18 -0700864 struct utimbuf times = { time, time };
865 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700866
867 /* use umask for permissions */
868 mode_t mask=umask(0000);
869 umask(mask);
870 int r2 = chmod(lpath, mode & ~mask);
871
872 return r1 ? : r2;
873}
874
Riley Andrewsc736a942014-12-12 13:12:36 -0800875/* Return a copy of the path string with / appended if needed */
876static char *add_slash_to_path(const char *path)
877{
878 if (path[strlen(path) - 1] != '/') {
879 size_t len = strlen(path) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800880 char *path_with_slash = reinterpret_cast<char*>(malloc(len));
Riley Andrewsc736a942014-12-12 13:12:36 -0800881 if (path_with_slash == NULL)
882 return NULL;
883 snprintf(path_with_slash, len, "%s/", path);
884 return path_with_slash;
885 } else {
886 return strdup(path);
887 }
888}
889
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800890static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700891 int copy_attrs)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800892{
893 copyinfo *filelist = 0;
894 copyinfo *ci, *next;
895 int pulled = 0;
896 int skipped = 0;
Riley Andrewsc736a942014-12-12 13:12:36 -0800897 char *rpath_clean = NULL;
898 char *lpath_clean = NULL;
899 int ret = 0;
900
901 if (rpath[0] == '\0' || lpath[0] == '\0') {
902 ret = -1;
903 goto finish;
904 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800905
906 /* Make sure that both directory paths end in a slash. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800907 rpath_clean = add_slash_to_path(rpath);
908 if (!rpath_clean) {
909 ret = -1;
910 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800911 }
Riley Andrewsc736a942014-12-12 13:12:36 -0800912 lpath_clean = add_slash_to_path(lpath);
913 if (!lpath_clean) {
914 ret = -1;
915 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800916 }
917
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800918 /* Recursively build the list of files to copy. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800919 fprintf(stderr, "pull: building file list...\n");
920 if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
921 ret = -1;
922 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800923 }
924
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800925 for (ci = filelist; ci != 0; ci = next) {
926 next = ci->next;
927 if (ci->flag == 0) {
928 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700929 if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800930 ret = -1;
931 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800932 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700933
934 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800935 ret = -1;
936 goto finish;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700937 }
The Android Open Source Project9ca14dc2009-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
Riley Andrewsc736a942014-12-12 13:12:36 -0800949finish:
950 free(lpath_clean);
951 free(rpath_clean);
952 return ret;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800953}
954
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700955int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800956{
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700957 unsigned mode, time;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800958 struct stat st;
959
Elliott Hughes04a98c22015-04-29 08:35:59 -0700960 std::string error;
961 int fd = adb_connect("sync:", &error);
962 if (fd < 0) {
963 fprintf(stderr,"error: %s\n", error.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800964 return 1;
965 }
966
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700967 if(sync_readtime(fd, rpath, &time, &mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800968 return 1;
969 }
970 if(mode == 0) {
971 fprintf(stderr,"remote object '%s' does not exist\n", rpath);
972 return 1;
973 }
974
Matt Fischer3ba90752010-01-04 16:18:50 -0600975 if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800976 if(stat(lpath, &st) == 0) {
977 if(S_ISDIR(st.st_mode)) {
978 /* if we're copying a remote file to a local directory,
979 ** we *really* want to copy to localdir + "/" + remotefilename
980 */
981 const char *name = adb_dirstop(rpath);
982 if(name == 0) {
983 name = rpath;
984 } else {
985 name++;
986 }
987 int tmplen = strlen(name) + strlen(lpath) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800988 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800989 if(tmp == 0) return 1;
990 snprintf(tmp, tmplen, "%s/%s", lpath, name);
991 lpath = tmp;
992 }
993 }
994 BEGIN();
Mark Lindner9f9d1452014-03-11 17:55:59 -0700995 if (sync_recv(fd, rpath, lpath, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800996 return 1;
997 } else {
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700998 if (copy_attrs && set_time_and_mode(lpath, time, mode))
999 return 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001000 END();
1001 sync_quit(fd);
1002 return 0;
1003 }
1004 } else if(S_ISDIR(mode)) {
1005 BEGIN();
Lajos Molnar4e23e3c2013-04-19 12:41:09 -07001006 if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001007 return 1;
1008 } else {
1009 END();
1010 sync_quit(fd);
1011 return 0;
1012 }
1013 } else {
1014 fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
1015 return 1;
1016 }
1017}
1018
Elliott Hughesc5a12b22015-04-21 10:17:07 -07001019int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001020{
Elliott Hughesc5a12b22015-04-21 10:17:07 -07001021 fprintf(stderr, "syncing %s...\n", rpath.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001022
Elliott Hughes04a98c22015-04-29 08:35:59 -07001023 std::string error;
1024 int fd = adb_connect("sync:", &error);
Elliott Hughesc5a12b22015-04-21 10:17:07 -07001025 if (fd < 0) {
Elliott Hughes04a98c22015-04-29 08:35:59 -07001026 fprintf(stderr, "error: %s\n", error.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001027 return 1;
1028 }
1029
1030 BEGIN();
Elliott Hughesc5a12b22015-04-21 10:17:07 -07001031 if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001032 return 1;
1033 } else {
1034 END();
1035 sync_quit(fd);
1036 return 0;
1037 }
1038}