blob: da800130e278ecaf680d41ddb22cb5a586a03767 [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>
Spencer Low803451e2015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albertb302d122015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albertb302d122015-02-24 15:51:19 -080027#include <time.h>
Greg Hackmann8b689142014-05-06 08:48:18 -070028#include <utime.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080029
30#include "sysdeps.h"
Dan Albertb302d122015-02-24 15:51:19 -080031
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080032#include "adb.h"
33#include "adb_client.h"
Dan Albert66a91b02015-02-24 21:26:58 -080034#include "adb_io.h"
Alex Valléee9163152015-05-06 17:22:25 -040035#include "adb_utils.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080036#include "file_sync_service.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080037
Elliott Hughesd189cfb2015-07-30 17:42:01 -070038#include <base/stringprintf.h>
39
Jeff Smith51d3fc12013-06-15 15:32:05 -050040static unsigned long long total_bytes;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080041static long long start_time;
42
43static long long NOW()
44{
45 struct timeval tv;
46 gettimeofday(&tv, 0);
47 return ((long long) tv.tv_usec) +
48 1000000LL * ((long long) tv.tv_sec);
49}
50
51static void BEGIN()
52{
53 total_bytes = 0;
54 start_time = NOW();
55}
56
57static void END()
58{
59 long long t = NOW() - start_time;
60 if(total_bytes == 0) return;
61
62 if (t == 0) /* prevent division by 0 :-) */
63 t = 1000000;
64
Mike Lockwoodeaf5a1e2010-12-14 23:07:32 -080065 fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
Jeff Smith51d3fc12013-06-15 15:32:05 -050066 ((total_bytes * 1000000LL) / t) / 1024LL,
67 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080068}
69
Spencer Low803451e2015-05-13 00:02:55 -070070static void print_transfer_progress(uint64_t bytes_current,
71 uint64_t bytes_total) {
Mark Lindner9f9d1452014-03-11 17:55:59 -070072 if (bytes_total == 0) return;
73
Spencer Low803451e2015-05-13 00:02:55 -070074 fprintf(stderr, "\rTransferring: %" PRIu64 "/%" PRIu64 " (%d%%)",
75 bytes_current, bytes_total,
Mark Lindner9f9d1452014-03-11 17:55:59 -070076 (int) (bytes_current * 100 / bytes_total));
77
78 if (bytes_current == bytes_total) {
79 fputc('\n', stderr);
80 }
81
82 fflush(stderr);
83}
84
Elliott Hughes712416a2015-05-05 18:26:10 -070085static void sync_quit(int fd) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080086 syncmsg msg;
87
88 msg.req.id = ID_QUIT;
89 msg.req.namelen = 0;
90
Dan Albert66a91b02015-02-24 21:26:58 -080091 WriteFdExactly(fd, &msg.req, sizeof(msg.req));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080092}
93
94typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
95
Elliott Hughes712416a2015-05-05 18:26:10 -070096static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
Elliott Hughesd189cfb2015-07-30 17:42:01 -070097 int len = strlen(path);
98 if (len > 1024) goto fail;
99
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800100 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800101 msg.req.id = ID_LIST;
102 msg.req.namelen = htoll(len);
103
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700104 if (!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800105 goto fail;
106 }
107
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700108 for (;;) {
109 if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
110 if (msg.dent.id == ID_DONE) return 0;
111 if (msg.dent.id != ID_DENT) break;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800112
113 len = ltohl(msg.dent.namelen);
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700114 if (len > 256) break;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800115
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700116 char buf[257];
117 if (!ReadFdExactly(fd, buf, len)) break;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800118 buf[len] = 0;
119
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700120 func(ltohl(msg.dent.mode), ltohl(msg.dent.size), ltohl(msg.dent.time), buf, cookie);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800121 }
122
123fail:
124 adb_close(fd);
125 return -1;
126}
127
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800128struct syncsendbuf {
129 unsigned id;
130 unsigned size;
131 char data[SYNC_DATA_MAX];
132};
133
134static syncsendbuf send_buffer;
135
Elliott Hughes712416a2015-05-05 18:26:10 -0700136static int sync_readtime(int fd, const char* path, unsigned int* timestamp, unsigned int* mode) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800137 syncmsg msg;
138 int len = strlen(path);
139
140 msg.req.id = ID_STAT;
141 msg.req.namelen = htoll(len);
142
Dan Albert66a91b02015-02-24 21:26:58 -0800143 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
144 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800145 return -1;
146 }
147
Dan Albert66a91b02015-02-24 21:26:58 -0800148 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800149 return -1;
150 }
151
152 if(msg.stat.id != ID_STAT) {
153 return -1;
154 }
155
156 *timestamp = ltohl(msg.stat.time);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700157 *mode = ltohl(msg.stat.mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800158 return 0;
159}
160
161static int sync_start_readtime(int fd, const char *path)
162{
163 syncmsg msg;
164 int len = strlen(path);
165
166 msg.req.id = ID_STAT;
167 msg.req.namelen = htoll(len);
168
Dan Albert66a91b02015-02-24 21:26:58 -0800169 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
170 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800171 return -1;
172 }
173
174 return 0;
175}
176
177static int sync_finish_readtime(int fd, unsigned int *timestamp,
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200178 unsigned int *mode, unsigned int *size)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800179{
180 syncmsg msg;
181
Dan Albert66a91b02015-02-24 21:26:58 -0800182 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800183 return -1;
184
185 if(msg.stat.id != ID_STAT)
186 return -1;
187
188 *timestamp = ltohl(msg.stat.time);
189 *mode = ltohl(msg.stat.mode);
190 *size = ltohl(msg.stat.size);
191
192 return 0;
193}
194
Elliott Hughes712416a2015-05-05 18:26:10 -0700195static int sync_readmode(int fd, const char* path, unsigned* mode) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800196 syncmsg msg;
197 int len = strlen(path);
198
199 msg.req.id = ID_STAT;
200 msg.req.namelen = htoll(len);
201
Dan Albert66a91b02015-02-24 21:26:58 -0800202 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
203 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800204 return -1;
205 }
206
Dan Albert66a91b02015-02-24 21:26:58 -0800207 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800208 return -1;
209 }
210
211 if(msg.stat.id != ID_STAT) {
212 return -1;
213 }
214
215 *mode = ltohl(msg.stat.mode);
216 return 0;
217}
218
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700219static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, bool show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800220{
221 int lfd, err = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700222 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800223
224 lfd = adb_open(path, O_RDONLY);
225 if(lfd < 0) {
226 fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
227 return -1;
228 }
229
Mark Lindner9f9d1452014-03-11 17:55:59 -0700230 if (show_progress) {
231 // Determine local file size.
232 struct stat st;
eric.yan466d3f42015-02-03 22:16:29 +0800233 if (stat(path, &st)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700234 fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
235 return -1;
236 }
237
238 size = st.st_size;
239 }
240
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800241 sbuf->id = ID_DATA;
242 for(;;) {
243 int ret;
244
245 ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
246 if(!ret)
247 break;
248
249 if(ret < 0) {
250 if(errno == EINTR)
251 continue;
252 fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
253 break;
254 }
255
256 sbuf->size = htoll(ret);
Dan Albert66a91b02015-02-24 21:26:58 -0800257 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800258 err = -1;
259 break;
260 }
261 total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700262
263 if (show_progress) {
264 print_transfer_progress(total_bytes, size);
265 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800266 }
267
268 adb_close(lfd);
269 return err;
270}
271
Mark Lindner9f9d1452014-03-11 17:55:59 -0700272static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700273 bool show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800274{
275 int err = 0;
276 int total = 0;
277
278 sbuf->id = ID_DATA;
279 while (total < size) {
280 int count = size - total;
281 if (count > SYNC_DATA_MAX) {
282 count = SYNC_DATA_MAX;
283 }
284
285 memcpy(sbuf->data, &file_buffer[total], count);
286 sbuf->size = htoll(count);
Dan Albert66a91b02015-02-24 21:26:58 -0800287 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800288 err = -1;
289 break;
290 }
291 total += count;
292 total_bytes += count;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700293
294 if (show_progress) {
295 print_transfer_progress(total, size);
296 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800297 }
298
299 return err;
300}
301
Elliott Hughes944e1d72015-01-12 14:26:36 -0800302#if defined(_WIN32)
303extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
304#else
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800305static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
306{
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700307 int len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
308 if (len < 0) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800309 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
310 return -1;
311 }
312 sbuf->data[len] = '\0';
313
314 sbuf->size = htoll(len + 1);
315 sbuf->id = ID_DATA;
316
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700317 if (!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800318 return -1;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700319 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800320
321 total_bytes += len + 1;
322
323 return 0;
324}
325#endif
326
327static int sync_send(int fd, const char *lpath, const char *rpath,
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700328 unsigned mtime, mode_t mode, bool show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800329{
330 syncmsg msg;
331 int len, r;
332 syncsendbuf *sbuf = &send_buffer;
333 char* file_buffer = NULL;
334 int size = 0;
335 char tmp[64];
336
337 len = strlen(rpath);
338 if(len > 1024) goto fail;
339
340 snprintf(tmp, sizeof(tmp), ",%d", mode);
341 r = strlen(tmp);
342
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800343 msg.req.id = ID_SEND;
344 msg.req.namelen = htoll(len + r);
345
Dan Albert66a91b02015-02-24 21:26:58 -0800346 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
347 !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800348 free(file_buffer);
349 goto fail;
350 }
351
352 if (file_buffer) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700353 write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800354 free(file_buffer);
355 } else if (S_ISREG(mode))
Mark Lindner9f9d1452014-03-11 17:55:59 -0700356 write_data_file(fd, lpath, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800357 else if (S_ISLNK(mode))
358 write_data_link(fd, lpath, sbuf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800359 else
360 goto fail;
361
362 msg.data.id = ID_DONE;
363 msg.data.size = htoll(mtime);
Dan Albert66a91b02015-02-24 21:26:58 -0800364 if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800365 goto fail;
366
Dan Albert66a91b02015-02-24 21:26:58 -0800367 if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800368 return -1;
369
370 if(msg.status.id != ID_OKAY) {
371 if(msg.status.id == ID_FAIL) {
372 len = ltohl(msg.status.msglen);
373 if(len > 256) len = 256;
Dan Albert66a91b02015-02-24 21:26:58 -0800374 if(!ReadFdExactly(fd, sbuf->data, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800375 return -1;
376 }
377 sbuf->data[len] = 0;
378 } else
379 strcpy(sbuf->data, "unknown reason");
380
381 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
382 return -1;
383 }
384
385 return 0;
386
387fail:
388 fprintf(stderr,"protocol failure\n");
389 adb_close(fd);
390 return -1;
391}
392
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700393static int sync_recv(int fd, const char* rpath, const char* lpath, bool show_progress) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800394 syncmsg msg;
395 int len;
396 int lfd = -1;
397 char *buffer = send_buffer.data;
398 unsigned id;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700399 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800400
401 len = strlen(rpath);
402 if(len > 1024) return -1;
403
Mark Lindner9f9d1452014-03-11 17:55:59 -0700404 if (show_progress) {
405 // Determine remote file size.
406 syncmsg stat_msg;
407 stat_msg.req.id = ID_STAT;
408 stat_msg.req.namelen = htoll(len);
409
Dan Albert66a91b02015-02-24 21:26:58 -0800410 if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
411 !WriteFdExactly(fd, rpath, len)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700412 return -1;
413 }
414
Dan Albert66a91b02015-02-24 21:26:58 -0800415 if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700416 return -1;
417 }
418
419 if (stat_msg.stat.id != ID_STAT) return -1;
420
421 size = ltohl(stat_msg.stat.size);
422 }
423
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800424 msg.req.id = ID_RECV;
425 msg.req.namelen = htoll(len);
Dan Albert66a91b02015-02-24 21:26:58 -0800426 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
427 !WriteFdExactly(fd, rpath, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800428 return -1;
429 }
430
Dan Albert66a91b02015-02-24 21:26:58 -0800431 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800432 return -1;
433 }
434 id = msg.data.id;
435
436 if((id == ID_DATA) || (id == ID_DONE)) {
437 adb_unlink(lpath);
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700438 mkdirs(lpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800439 lfd = adb_creat(lpath, 0644);
440 if(lfd < 0) {
441 fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
442 return -1;
443 }
444 goto handle_data;
445 } else {
446 goto remote_error;
447 }
448
449 for(;;) {
Dan Albert66a91b02015-02-24 21:26:58 -0800450 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800451 return -1;
452 }
453 id = msg.data.id;
454
455 handle_data:
456 len = ltohl(msg.data.size);
457 if(id == ID_DONE) break;
458 if(id != ID_DATA) goto remote_error;
459 if(len > SYNC_DATA_MAX) {
460 fprintf(stderr,"data overrun\n");
461 adb_close(lfd);
462 return -1;
463 }
464
Dan Albert66a91b02015-02-24 21:26:58 -0800465 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800466 adb_close(lfd);
467 return -1;
468 }
469
Dan Albert66a91b02015-02-24 21:26:58 -0800470 if(!WriteFdExactly(lfd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800471 fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
472 adb_close(lfd);
473 return -1;
474 }
475
476 total_bytes += len;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700477
478 if (show_progress) {
479 print_transfer_progress(total_bytes, size);
480 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800481 }
482
483 adb_close(lfd);
484 return 0;
485
486remote_error:
487 adb_close(lfd);
488 adb_unlink(lpath);
489
490 if(id == ID_FAIL) {
491 len = ltohl(msg.data.size);
492 if(len > 256) len = 256;
Dan Albert66a91b02015-02-24 21:26:58 -0800493 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800494 return -1;
495 }
496 buffer[len] = 0;
497 } else {
498 memcpy(buffer, &id, 4);
499 buffer[4] = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800500 }
501 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
502 return 0;
503}
504
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800505/* --- */
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800506static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
507 const char *name, void *cookie)
508{
509 printf("%08x %08x %08x %s\n", mode, size, time, name);
510}
511
Elliott Hughes04a98c22015-04-29 08:35:59 -0700512int do_sync_ls(const char* path) {
513 std::string error;
514 int fd = adb_connect("sync:", &error);
515 if (fd < 0) {
516 fprintf(stderr,"error: %s\n", error.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800517 return 1;
518 }
519
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700520 if (sync_ls(fd, path, do_sync_ls_cb, 0)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800521 return 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800522 }
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700523
524 sync_quit(fd);
525 return 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800526}
527
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800528struct copyinfo
529{
530 copyinfo *next;
531 const char *src;
532 const char *dst;
533 unsigned int time;
534 unsigned int mode;
535 unsigned int size;
536 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800537};
538
Elliott Hughes712416a2015-05-05 18:26:10 -0700539static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800540 int slen = strlen(spath);
541 int dlen = strlen(dpath);
542 int nlen = strlen(name);
543 int ssize = slen + nlen + 2;
544 int dsize = dlen + nlen + 2;
545
Elliott Hughes712416a2015-05-05 18:26:10 -0700546 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800547 if(ci == 0) {
548 fprintf(stderr,"out of memory\n");
549 abort();
550 }
551
552 ci->next = 0;
553 ci->time = 0;
554 ci->mode = 0;
555 ci->size = 0;
556 ci->flag = 0;
557 ci->src = (const char*)(ci + 1);
558 ci->dst = ci->src + ssize;
559 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
560 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
561
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800562 return ci;
563}
564
565
566static int local_build_list(copyinfo **filelist,
567 const char *lpath, const char *rpath)
568{
569 DIR *d;
570 struct dirent *de;
571 struct stat st;
572 copyinfo *dirlist = 0;
573 copyinfo *ci, *next;
574
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800575 d = opendir(lpath);
576 if(d == 0) {
577 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
578 return -1;
579 }
580
581 while((de = readdir(d))) {
582 char stat_path[PATH_MAX];
583 char *name = de->d_name;
584
585 if(name[0] == '.') {
586 if(name[1] == 0) continue;
587 if((name[1] == '.') && (name[2] == 0)) continue;
588 }
589
590 /*
591 * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
592 * always returns DT_UNKNOWN, so we just use stat() for all cases.
593 */
594 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
595 continue;
596 strcpy(stat_path, lpath);
597 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800598
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700599 if(!lstat(stat_path, &st)) {
600 if (S_ISDIR(st.st_mode)) {
601 ci = mkcopyinfo(lpath, rpath, name, 1);
602 ci->next = dirlist;
603 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800604 } else {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700605 ci = mkcopyinfo(lpath, rpath, name, 0);
606 if(lstat(ci->src, &st)) {
607 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
608 free(ci);
609 closedir(d);
610 return -1;
611 }
612 if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
613 fprintf(stderr, "skipping special file '%s'\n", ci->src);
614 free(ci);
615 } else {
616 ci->time = st.st_mtime;
617 ci->mode = st.st_mode;
618 ci->size = st.st_size;
619 ci->next = *filelist;
620 *filelist = ci;
621 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800622 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700623 } else {
624 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800625 }
626 }
627
628 closedir(d);
629
630 for(ci = dirlist; ci != 0; ci = next) {
631 next = ci->next;
632 local_build_list(filelist, ci->src, ci->dst);
633 free(ci);
634 }
635
636 return 0;
637}
638
639
Anthony Newnamdd2db142010-02-22 08:36:49 -0600640static 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 -0800641{
642 copyinfo *filelist = 0;
643 copyinfo *ci, *next;
644 int pushed = 0;
645 int skipped = 0;
646
647 if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
648 if(lpath[strlen(lpath) - 1] != '/') {
649 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800650 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800651 if(tmp == 0) return -1;
652 snprintf(tmp, tmplen, "%s/",lpath);
653 lpath = tmp;
654 }
655 if(rpath[strlen(rpath) - 1] != '/') {
656 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800657 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800658 if(tmp == 0) return -1;
659 snprintf(tmp, tmplen, "%s/",rpath);
660 rpath = tmp;
661 }
662
663 if(local_build_list(&filelist, lpath, rpath)) {
664 return -1;
665 }
666
667 if(checktimestamps){
668 for(ci = filelist; ci != 0; ci = ci->next) {
669 if(sync_start_readtime(fd, ci->dst)) {
670 return 1;
671 }
672 }
673 for(ci = filelist; ci != 0; ci = ci->next) {
674 unsigned int timestamp, mode, size;
675 if(sync_finish_readtime(fd, &timestamp, &mode, &size))
676 return 1;
677 if(size == ci->size) {
678 /* for links, we cannot update the atime/mtime */
679 if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
680 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
681 ci->flag = 1;
682 }
683 }
684 }
685 for(ci = filelist; ci != 0; ci = next) {
686 next = ci->next;
687 if(ci->flag == 0) {
Anthony Newnamdd2db142010-02-22 08:36:49 -0600688 fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
689 if(!listonly &&
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700690 sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
Mark Lindner9f9d1452014-03-11 17:55:59 -0700691 0 /* no show progress */)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800692 return 1;
693 }
694 pushed++;
695 } else {
696 skipped++;
697 }
698 free(ci);
699 }
700
701 fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
702 pushed, (pushed == 1) ? "" : "s",
703 skipped, (skipped == 1) ? "" : "s");
704
705 return 0;
706}
707
708
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700709int do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
Elliott Hughes04a98c22015-04-29 08:35:59 -0700710 std::string error;
711 int fd = adb_connect("sync:", &error);
712 if (fd < 0) {
713 fprintf(stderr,"error: %s\n", error.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800714 return 1;
715 }
716
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700717 struct stat st;
718 if (stat(lpath, &st)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800719 fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
720 sync_quit(fd);
721 return 1;
722 }
723
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700724 if (S_ISDIR(st.st_mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800725 BEGIN();
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700726 if (copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800727 return 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800728 }
729 } else {
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700730 unsigned mode;
731 if (sync_readmode(fd, rpath, &mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800732 return 1;
733 }
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700734 std::string path_holder;
735 if ((mode != 0) && S_ISDIR(mode)) {
736 // If we're copying a local file to a remote directory,
737 // we really want to copy to remote_dir + "/" + local_filename.
738 path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
739 rpath = path_holder.c_str();
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800740 }
741 BEGIN();
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700742 if (sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800743 return 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800744 }
745 }
746
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700747 END();
748 sync_quit(fd);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800749 return 0;
750}
751
752
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700753struct sync_ls_build_list_cb_args {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800754 copyinfo **filelist;
755 copyinfo **dirlist;
756 const char *rpath;
757 const char *lpath;
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700758};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800759
Elliott Hughes712416a2015-05-05 18:26:10 -0700760static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
761 const char* name, void* cookie)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800762{
763 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
764 copyinfo *ci;
765
766 if (S_ISDIR(mode)) {
767 copyinfo **dirlist = args->dirlist;
768
769 /* Don't try recursing down "." or ".." */
770 if (name[0] == '.') {
771 if (name[1] == '\0') return;
772 if ((name[1] == '.') && (name[2] == '\0')) return;
773 }
774
775 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
776 ci->next = *dirlist;
777 *dirlist = ci;
778 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
779 copyinfo **filelist = args->filelist;
780
781 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
782 ci->time = time;
783 ci->mode = mode;
784 ci->size = size;
785 ci->next = *filelist;
786 *filelist = ci;
787 } else {
788 fprintf(stderr, "skipping special file '%s'\n", name);
789 }
790}
791
792static int remote_build_list(int syncfd, copyinfo **filelist,
793 const char *rpath, const char *lpath)
794{
795 copyinfo *dirlist = NULL;
796 sync_ls_build_list_cb_args args;
797
798 args.filelist = filelist;
799 args.dirlist = &dirlist;
800 args.rpath = rpath;
801 args.lpath = lpath;
802
803 /* Put the files/dirs in rpath on the lists. */
804 if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
805 return 1;
806 }
807
808 /* Recurse into each directory we found. */
809 while (dirlist != NULL) {
810 copyinfo *next = dirlist->next;
811 if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
812 return 1;
813 }
814 free(dirlist);
815 dirlist = next;
816 }
817
818 return 0;
819}
820
Dan Albertf30d73c2015-02-25 17:51:28 -0800821static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700822{
Greg Hackmann8b689142014-05-06 08:48:18 -0700823 struct utimbuf times = { time, time };
824 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700825
826 /* use umask for permissions */
827 mode_t mask=umask(0000);
828 umask(mask);
829 int r2 = chmod(lpath, mode & ~mask);
830
831 return r1 ? : r2;
832}
833
Riley Andrewsc736a942014-12-12 13:12:36 -0800834/* Return a copy of the path string with / appended if needed */
835static char *add_slash_to_path(const char *path)
836{
837 if (path[strlen(path) - 1] != '/') {
838 size_t len = strlen(path) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800839 char *path_with_slash = reinterpret_cast<char*>(malloc(len));
Riley Andrewsc736a942014-12-12 13:12:36 -0800840 if (path_with_slash == NULL)
841 return NULL;
842 snprintf(path_with_slash, len, "%s/", path);
843 return path_with_slash;
844 } else {
845 return strdup(path);
846 }
847}
848
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800849static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700850 int copy_attrs)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800851{
852 copyinfo *filelist = 0;
853 copyinfo *ci, *next;
854 int pulled = 0;
855 int skipped = 0;
Riley Andrewsc736a942014-12-12 13:12:36 -0800856 char *rpath_clean = NULL;
857 char *lpath_clean = NULL;
858 int ret = 0;
859
860 if (rpath[0] == '\0' || lpath[0] == '\0') {
861 ret = -1;
862 goto finish;
863 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800864
865 /* Make sure that both directory paths end in a slash. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800866 rpath_clean = add_slash_to_path(rpath);
867 if (!rpath_clean) {
868 ret = -1;
869 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800870 }
Riley Andrewsc736a942014-12-12 13:12:36 -0800871 lpath_clean = add_slash_to_path(lpath);
872 if (!lpath_clean) {
873 ret = -1;
874 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800875 }
876
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800877 /* Recursively build the list of files to copy. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800878 fprintf(stderr, "pull: building file list...\n");
879 if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
880 ret = -1;
881 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800882 }
883
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800884 for (ci = filelist; ci != 0; ci = next) {
885 next = ci->next;
886 if (ci->flag == 0) {
887 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700888 if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800889 ret = -1;
890 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800891 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700892
893 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800894 ret = -1;
895 goto finish;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700896 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800897 pulled++;
898 } else {
899 skipped++;
900 }
901 free(ci);
902 }
903
904 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
905 pulled, (pulled == 1) ? "" : "s",
906 skipped, (skipped == 1) ? "" : "s");
907
Riley Andrewsc736a942014-12-12 13:12:36 -0800908finish:
909 free(lpath_clean);
910 free(rpath_clean);
911 return ret;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800912}
913
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700914int do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
Elliott Hughes04a98c22015-04-29 08:35:59 -0700915 std::string error;
916 int fd = adb_connect("sync:", &error);
917 if (fd < 0) {
918 fprintf(stderr,"error: %s\n", error.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800919 return 1;
920 }
921
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700922 unsigned mode, time;
923 if (sync_readtime(fd, rpath, &time, &mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800924 return 1;
925 }
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700926 if (mode == 0) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800927 fprintf(stderr,"remote object '%s' does not exist\n", rpath);
928 return 1;
929 }
930
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700931 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
932 std::string path_holder;
933 struct stat st;
934 if (stat(lpath, &st) == 0) {
935 if (S_ISDIR(st.st_mode)) {
936 // If we're copying a remote file to a local directory,
937 // we really want to copy to local_dir + "/" + basename(remote).
938 path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
939 lpath = path_holder.c_str();
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800940 }
941 }
942 BEGIN();
Mark Lindner9f9d1452014-03-11 17:55:59 -0700943 if (sync_recv(fd, rpath, lpath, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800944 return 1;
945 } else {
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700946 if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700947 return 1;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700948 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800949 }
950 } else if(S_ISDIR(mode)) {
951 BEGIN();
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700952 if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800953 return 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800954 }
955 } else {
956 fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
957 return 1;
958 }
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700959 END();
960 sync_quit(fd);
961 return 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800962}
963
Elliott Hughesc5a12b22015-04-21 10:17:07 -0700964int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800965{
Elliott Hughesc5a12b22015-04-21 10:17:07 -0700966 fprintf(stderr, "syncing %s...\n", rpath.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800967
Elliott Hughes04a98c22015-04-29 08:35:59 -0700968 std::string error;
969 int fd = adb_connect("sync:", &error);
Elliott Hughesc5a12b22015-04-21 10:17:07 -0700970 if (fd < 0) {
Elliott Hughes04a98c22015-04-29 08:35:59 -0700971 fprintf(stderr, "error: %s\n", error.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800972 return 1;
973 }
974
975 BEGIN();
Elliott Hughesc5a12b22015-04-21 10:17:07 -0700976 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 -0800977 return 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800978 }
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700979 END();
980 sync_quit(fd);
981 return 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800982}