blob: 49d42a38f0a5a2e24856f20beec0fe13e83647a5 [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
Dan Albert76649012015-02-24 15:51:19 -080017#include <dirent.h>
18#include <errno.h>
Spencer Low6001c872015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albert76649012015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albert76649012015-02-24 15:51:19 -080027#include <time.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"
Dan Albert76649012015-02-24 15:51:19 -080031
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080032#include "adb.h"
33#include "adb_client.h"
Dan Albertcc731cc2015-02-24 21:26:58 -080034#include "adb_io.h"
Alex Vallée14216142015-05-06 17:22:25 -040035#include "adb_utils.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036#include "file_sync_service.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080037
Jeff Smithd9a14302013-06-15 15:32:05 -050038static unsigned long long total_bytes;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080039static long long start_time;
40
41static long long NOW()
42{
43 struct timeval tv;
44 gettimeofday(&tv, 0);
45 return ((long long) tv.tv_usec) +
46 1000000LL * ((long long) tv.tv_sec);
47}
48
49static void BEGIN()
50{
51 total_bytes = 0;
52 start_time = NOW();
53}
54
55static void END()
56{
57 long long t = NOW() - start_time;
58 if(total_bytes == 0) return;
59
60 if (t == 0) /* prevent division by 0 :-) */
61 t = 1000000;
62
Mike Lockwoodee878752010-12-14 23:07:32 -080063 fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
Jeff Smithd9a14302013-06-15 15:32:05 -050064 ((total_bytes * 1000000LL) / t) / 1024LL,
65 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080066}
67
Spencer Low6001c872015-05-13 00:02:55 -070068static void print_transfer_progress(uint64_t bytes_current,
69 uint64_t bytes_total) {
Mark Lindner76f2a932014-03-11 17:55:59 -070070 if (bytes_total == 0) return;
71
Spencer Low6001c872015-05-13 00:02:55 -070072 fprintf(stderr, "\rTransferring: %" PRIu64 "/%" PRIu64 " (%d%%)",
73 bytes_current, bytes_total,
Mark Lindner76f2a932014-03-11 17:55:59 -070074 (int) (bytes_current * 100 / bytes_total));
75
76 if (bytes_current == bytes_total) {
77 fputc('\n', stderr);
78 }
79
80 fflush(stderr);
81}
82
Elliott Hughes3edd54b2015-05-05 18:26:10 -070083static void sync_quit(int fd) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080084 syncmsg msg;
85
86 msg.req.id = ID_QUIT;
87 msg.req.namelen = 0;
88
Dan Albertcc731cc2015-02-24 21:26:58 -080089 WriteFdExactly(fd, &msg.req, sizeof(msg.req));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080090}
91
92typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
93
Elliott Hughes3edd54b2015-05-05 18:26:10 -070094static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080095 syncmsg msg;
96 char buf[257];
97 int len;
98
99 len = strlen(path);
100 if(len > 1024) goto fail;
101
102 msg.req.id = ID_LIST;
103 msg.req.namelen = htoll(len);
104
Dan Albertcc731cc2015-02-24 21:26:58 -0800105 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
106 !WriteFdExactly(fd, path, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800107 goto fail;
108 }
109
110 for(;;) {
Dan Albertcc731cc2015-02-24 21:26:58 -0800111 if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800112 if(msg.dent.id == ID_DONE) return 0;
113 if(msg.dent.id != ID_DENT) break;
114
115 len = ltohl(msg.dent.namelen);
116 if(len > 256) break;
117
Dan Albertcc731cc2015-02-24 21:26:58 -0800118 if(!ReadFdExactly(fd, buf, len)) break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800119 buf[len] = 0;
120
121 func(ltohl(msg.dent.mode),
122 ltohl(msg.dent.size),
123 ltohl(msg.dent.time),
124 buf, cookie);
125 }
126
127fail:
128 adb_close(fd);
129 return -1;
130}
131
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800132struct syncsendbuf {
133 unsigned id;
134 unsigned size;
135 char data[SYNC_DATA_MAX];
136};
137
138static syncsendbuf send_buffer;
139
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700140static int sync_readtime(int fd, const char* path, unsigned int* timestamp, unsigned int* mode) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800141 syncmsg msg;
142 int len = strlen(path);
143
144 msg.req.id = ID_STAT;
145 msg.req.namelen = htoll(len);
146
Dan Albertcc731cc2015-02-24 21:26:58 -0800147 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
148 !WriteFdExactly(fd, path, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800149 return -1;
150 }
151
Dan Albertcc731cc2015-02-24 21:26:58 -0800152 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800153 return -1;
154 }
155
156 if(msg.stat.id != ID_STAT) {
157 return -1;
158 }
159
160 *timestamp = ltohl(msg.stat.time);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700161 *mode = ltohl(msg.stat.mode);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800162 return 0;
163}
164
165static int sync_start_readtime(int fd, const char *path)
166{
167 syncmsg msg;
168 int len = strlen(path);
169
170 msg.req.id = ID_STAT;
171 msg.req.namelen = htoll(len);
172
Dan Albertcc731cc2015-02-24 21:26:58 -0800173 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
174 !WriteFdExactly(fd, path, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800175 return -1;
176 }
177
178 return 0;
179}
180
181static int sync_finish_readtime(int fd, unsigned int *timestamp,
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200182 unsigned int *mode, unsigned int *size)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800183{
184 syncmsg msg;
185
Dan Albertcc731cc2015-02-24 21:26:58 -0800186 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800187 return -1;
188
189 if(msg.stat.id != ID_STAT)
190 return -1;
191
192 *timestamp = ltohl(msg.stat.time);
193 *mode = ltohl(msg.stat.mode);
194 *size = ltohl(msg.stat.size);
195
196 return 0;
197}
198
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700199static int sync_readmode(int fd, const char* path, unsigned* mode) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800200 syncmsg msg;
201 int len = strlen(path);
202
203 msg.req.id = ID_STAT;
204 msg.req.namelen = htoll(len);
205
Dan Albertcc731cc2015-02-24 21:26:58 -0800206 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
207 !WriteFdExactly(fd, path, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800208 return -1;
209 }
210
Dan Albertcc731cc2015-02-24 21:26:58 -0800211 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800212 return -1;
213 }
214
215 if(msg.stat.id != ID_STAT) {
216 return -1;
217 }
218
219 *mode = ltohl(msg.stat.mode);
220 return 0;
221}
222
Mark Lindner76f2a932014-03-11 17:55:59 -0700223static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800224{
225 int lfd, err = 0;
Mark Lindner76f2a932014-03-11 17:55:59 -0700226 unsigned long long size = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800227
228 lfd = adb_open(path, O_RDONLY);
229 if(lfd < 0) {
230 fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
231 return -1;
232 }
233
Mark Lindner76f2a932014-03-11 17:55:59 -0700234 if (show_progress) {
235 // Determine local file size.
236 struct stat st;
eric.yana8592192015-02-03 22:16:29 +0800237 if (stat(path, &st)) {
Mark Lindner76f2a932014-03-11 17:55:59 -0700238 fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
239 return -1;
240 }
241
242 size = st.st_size;
243 }
244
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800245 sbuf->id = ID_DATA;
246 for(;;) {
247 int ret;
248
249 ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
250 if(!ret)
251 break;
252
253 if(ret < 0) {
254 if(errno == EINTR)
255 continue;
256 fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
257 break;
258 }
259
260 sbuf->size = htoll(ret);
Dan Albertcc731cc2015-02-24 21:26:58 -0800261 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800262 err = -1;
263 break;
264 }
265 total_bytes += ret;
Mark Lindner76f2a932014-03-11 17:55:59 -0700266
267 if (show_progress) {
268 print_transfer_progress(total_bytes, size);
269 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800270 }
271
272 adb_close(lfd);
273 return err;
274}
275
Mark Lindner76f2a932014-03-11 17:55:59 -0700276static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
277 int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800278{
279 int err = 0;
280 int total = 0;
281
282 sbuf->id = ID_DATA;
283 while (total < size) {
284 int count = size - total;
285 if (count > SYNC_DATA_MAX) {
286 count = SYNC_DATA_MAX;
287 }
288
289 memcpy(sbuf->data, &file_buffer[total], count);
290 sbuf->size = htoll(count);
Dan Albertcc731cc2015-02-24 21:26:58 -0800291 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800292 err = -1;
293 break;
294 }
295 total += count;
296 total_bytes += count;
Mark Lindner76f2a932014-03-11 17:55:59 -0700297
298 if (show_progress) {
299 print_transfer_progress(total, size);
300 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800301 }
302
303 return err;
304}
305
Elliott Hughes0a049b12015-01-12 14:26:36 -0800306#if defined(_WIN32)
307extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
308#else
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800309static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
310{
311 int len, ret;
312
313 len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
314 if(len < 0) {
315 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
316 return -1;
317 }
318 sbuf->data[len] = '\0';
319
320 sbuf->size = htoll(len + 1);
321 sbuf->id = ID_DATA;
322
Dan Albertcc731cc2015-02-24 21:26:58 -0800323 ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800324 if(ret)
325 return -1;
326
327 total_bytes += len + 1;
328
329 return 0;
330}
331#endif
332
333static int sync_send(int fd, const char *lpath, const char *rpath,
Jeff Sharkey960df972014-06-09 17:30:57 -0700334 unsigned mtime, mode_t mode, int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800335{
336 syncmsg msg;
337 int len, r;
338 syncsendbuf *sbuf = &send_buffer;
339 char* file_buffer = NULL;
340 int size = 0;
341 char tmp[64];
342
343 len = strlen(rpath);
344 if(len > 1024) goto fail;
345
346 snprintf(tmp, sizeof(tmp), ",%d", mode);
347 r = strlen(tmp);
348
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800349 msg.req.id = ID_SEND;
350 msg.req.namelen = htoll(len + r);
351
Dan Albertcc731cc2015-02-24 21:26:58 -0800352 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
353 !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800354 free(file_buffer);
355 goto fail;
356 }
357
358 if (file_buffer) {
Mark Lindner76f2a932014-03-11 17:55:59 -0700359 write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800360 free(file_buffer);
361 } else if (S_ISREG(mode))
Mark Lindner76f2a932014-03-11 17:55:59 -0700362 write_data_file(fd, lpath, sbuf, show_progress);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800363 else if (S_ISLNK(mode))
364 write_data_link(fd, lpath, sbuf);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800365 else
366 goto fail;
367
368 msg.data.id = ID_DONE;
369 msg.data.size = htoll(mtime);
Dan Albertcc731cc2015-02-24 21:26:58 -0800370 if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800371 goto fail;
372
Dan Albertcc731cc2015-02-24 21:26:58 -0800373 if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800374 return -1;
375
376 if(msg.status.id != ID_OKAY) {
377 if(msg.status.id == ID_FAIL) {
378 len = ltohl(msg.status.msglen);
379 if(len > 256) len = 256;
Dan Albertcc731cc2015-02-24 21:26:58 -0800380 if(!ReadFdExactly(fd, sbuf->data, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800381 return -1;
382 }
383 sbuf->data[len] = 0;
384 } else
385 strcpy(sbuf->data, "unknown reason");
386
387 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
388 return -1;
389 }
390
391 return 0;
392
393fail:
394 fprintf(stderr,"protocol failure\n");
395 adb_close(fd);
396 return -1;
397}
398
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700399static int sync_recv(int fd, const char* rpath, const char* lpath, int show_progress) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800400 syncmsg msg;
401 int len;
402 int lfd = -1;
403 char *buffer = send_buffer.data;
404 unsigned id;
Mark Lindner76f2a932014-03-11 17:55:59 -0700405 unsigned long long size = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800406
407 len = strlen(rpath);
408 if(len > 1024) return -1;
409
Mark Lindner76f2a932014-03-11 17:55:59 -0700410 if (show_progress) {
411 // Determine remote file size.
412 syncmsg stat_msg;
413 stat_msg.req.id = ID_STAT;
414 stat_msg.req.namelen = htoll(len);
415
Dan Albertcc731cc2015-02-24 21:26:58 -0800416 if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
417 !WriteFdExactly(fd, rpath, len)) {
Mark Lindner76f2a932014-03-11 17:55:59 -0700418 return -1;
419 }
420
Dan Albertcc731cc2015-02-24 21:26:58 -0800421 if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
Mark Lindner76f2a932014-03-11 17:55:59 -0700422 return -1;
423 }
424
425 if (stat_msg.stat.id != ID_STAT) return -1;
426
427 size = ltohl(stat_msg.stat.size);
428 }
429
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800430 msg.req.id = ID_RECV;
431 msg.req.namelen = htoll(len);
Dan Albertcc731cc2015-02-24 21:26:58 -0800432 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
433 !WriteFdExactly(fd, rpath, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800434 return -1;
435 }
436
Dan Albertcc731cc2015-02-24 21:26:58 -0800437 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800438 return -1;
439 }
440 id = msg.data.id;
441
442 if((id == ID_DATA) || (id == ID_DONE)) {
443 adb_unlink(lpath);
Mark Salyzyn60299df2014-04-30 09:10:31 -0700444 mkdirs(lpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800445 lfd = adb_creat(lpath, 0644);
446 if(lfd < 0) {
447 fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
448 return -1;
449 }
450 goto handle_data;
451 } else {
452 goto remote_error;
453 }
454
455 for(;;) {
Dan Albertcc731cc2015-02-24 21:26:58 -0800456 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800457 return -1;
458 }
459 id = msg.data.id;
460
461 handle_data:
462 len = ltohl(msg.data.size);
463 if(id == ID_DONE) break;
464 if(id != ID_DATA) goto remote_error;
465 if(len > SYNC_DATA_MAX) {
466 fprintf(stderr,"data overrun\n");
467 adb_close(lfd);
468 return -1;
469 }
470
Dan Albertcc731cc2015-02-24 21:26:58 -0800471 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800472 adb_close(lfd);
473 return -1;
474 }
475
Dan Albertcc731cc2015-02-24 21:26:58 -0800476 if(!WriteFdExactly(lfd, buffer, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800477 fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
478 adb_close(lfd);
479 return -1;
480 }
481
482 total_bytes += len;
Mark Lindner76f2a932014-03-11 17:55:59 -0700483
484 if (show_progress) {
485 print_transfer_progress(total_bytes, size);
486 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800487 }
488
489 adb_close(lfd);
490 return 0;
491
492remote_error:
493 adb_close(lfd);
494 adb_unlink(lpath);
495
496 if(id == ID_FAIL) {
497 len = ltohl(msg.data.size);
498 if(len > 256) len = 256;
Dan Albertcc731cc2015-02-24 21:26:58 -0800499 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800500 return -1;
501 }
502 buffer[len] = 0;
503 } else {
504 memcpy(buffer, &id, 4);
505 buffer[4] = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800506 }
507 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
508 return 0;
509}
510
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800511/* --- */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800512static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
513 const char *name, void *cookie)
514{
515 printf("%08x %08x %08x %s\n", mode, size, time, name);
516}
517
Elliott Hughes078f0fc2015-04-29 08:35:59 -0700518int do_sync_ls(const char* path) {
519 std::string error;
520 int fd = adb_connect("sync:", &error);
521 if (fd < 0) {
522 fprintf(stderr,"error: %s\n", error.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800523 return 1;
524 }
525
526 if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
527 return 1;
528 } else {
529 sync_quit(fd);
530 return 0;
531 }
532}
533
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800534struct copyinfo
535{
536 copyinfo *next;
537 const char *src;
538 const char *dst;
539 unsigned int time;
540 unsigned int mode;
541 unsigned int size;
542 int flag;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800543};
544
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700545static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800546 int slen = strlen(spath);
547 int dlen = strlen(dpath);
548 int nlen = strlen(name);
549 int ssize = slen + nlen + 2;
550 int dsize = dlen + nlen + 2;
551
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700552 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800553 if(ci == 0) {
554 fprintf(stderr,"out of memory\n");
555 abort();
556 }
557
558 ci->next = 0;
559 ci->time = 0;
560 ci->mode = 0;
561 ci->size = 0;
562 ci->flag = 0;
563 ci->src = (const char*)(ci + 1);
564 ci->dst = ci->src + ssize;
565 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
566 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
567
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800568 return ci;
569}
570
571
572static int local_build_list(copyinfo **filelist,
573 const char *lpath, const char *rpath)
574{
575 DIR *d;
576 struct dirent *de;
577 struct stat st;
578 copyinfo *dirlist = 0;
579 copyinfo *ci, *next;
580
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800581 d = opendir(lpath);
582 if(d == 0) {
583 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
584 return -1;
585 }
586
587 while((de = readdir(d))) {
588 char stat_path[PATH_MAX];
589 char *name = de->d_name;
590
591 if(name[0] == '.') {
592 if(name[1] == 0) continue;
593 if((name[1] == '.') && (name[2] == 0)) continue;
594 }
595
596 /*
597 * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
598 * always returns DT_UNKNOWN, so we just use stat() for all cases.
599 */
600 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
601 continue;
602 strcpy(stat_path, lpath);
603 strcat(stat_path, de->d_name);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800604
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700605 if(!lstat(stat_path, &st)) {
606 if (S_ISDIR(st.st_mode)) {
607 ci = mkcopyinfo(lpath, rpath, name, 1);
608 ci->next = dirlist;
609 dirlist = ci;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800610 } else {
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700611 ci = mkcopyinfo(lpath, rpath, name, 0);
612 if(lstat(ci->src, &st)) {
613 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
614 free(ci);
615 closedir(d);
616 return -1;
617 }
618 if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
619 fprintf(stderr, "skipping special file '%s'\n", ci->src);
620 free(ci);
621 } else {
622 ci->time = st.st_mtime;
623 ci->mode = st.st_mode;
624 ci->size = st.st_size;
625 ci->next = *filelist;
626 *filelist = ci;
627 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800628 }
Daniel Rosenberg686bce62014-06-30 20:29:40 -0700629 } else {
630 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800631 }
632 }
633
634 closedir(d);
635
636 for(ci = dirlist; ci != 0; ci = next) {
637 next = ci->next;
638 local_build_list(filelist, ci->src, ci->dst);
639 free(ci);
640 }
641
642 return 0;
643}
644
645
Anthony Newnam705c9442010-02-22 08:36:49 -0600646static 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 -0800647{
648 copyinfo *filelist = 0;
649 copyinfo *ci, *next;
650 int pushed = 0;
651 int skipped = 0;
652
653 if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
654 if(lpath[strlen(lpath) - 1] != '/') {
655 int tmplen = strlen(lpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800656 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800657 if(tmp == 0) return -1;
658 snprintf(tmp, tmplen, "%s/",lpath);
659 lpath = tmp;
660 }
661 if(rpath[strlen(rpath) - 1] != '/') {
662 int tmplen = strlen(rpath)+2;
Dan Albertbac34742015-02-25 17:51:28 -0800663 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800664 if(tmp == 0) return -1;
665 snprintf(tmp, tmplen, "%s/",rpath);
666 rpath = tmp;
667 }
668
669 if(local_build_list(&filelist, lpath, rpath)) {
670 return -1;
671 }
672
673 if(checktimestamps){
674 for(ci = filelist; ci != 0; ci = ci->next) {
675 if(sync_start_readtime(fd, ci->dst)) {
676 return 1;
677 }
678 }
679 for(ci = filelist; ci != 0; ci = ci->next) {
680 unsigned int timestamp, mode, size;
681 if(sync_finish_readtime(fd, &timestamp, &mode, &size))
682 return 1;
683 if(size == ci->size) {
684 /* for links, we cannot update the atime/mtime */
685 if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
686 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
687 ci->flag = 1;
688 }
689 }
690 }
691 for(ci = filelist; ci != 0; ci = next) {
692 next = ci->next;
693 if(ci->flag == 0) {
Anthony Newnam705c9442010-02-22 08:36:49 -0600694 fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
695 if(!listonly &&
Jeff Sharkey960df972014-06-09 17:30:57 -0700696 sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
Mark Lindner76f2a932014-03-11 17:55:59 -0700697 0 /* no show progress */)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800698 return 1;
699 }
700 pushed++;
701 } else {
702 skipped++;
703 }
704 free(ci);
705 }
706
707 fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
708 pushed, (pushed == 1) ? "" : "s",
709 skipped, (skipped == 1) ? "" : "s");
710
711 return 0;
712}
713
714
Jeff Sharkey960df972014-06-09 17:30:57 -0700715int do_sync_push(const char *lpath, const char *rpath, int show_progress)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800716{
717 struct stat st;
718 unsigned mode;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800719
Elliott Hughes078f0fc2015-04-29 08:35:59 -0700720 std::string error;
721 int fd = adb_connect("sync:", &error);
722 if (fd < 0) {
723 fprintf(stderr,"error: %s\n", error.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800724 return 1;
725 }
726
727 if(stat(lpath, &st)) {
728 fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
729 sync_quit(fd);
730 return 1;
731 }
732
733 if(S_ISDIR(st.st_mode)) {
734 BEGIN();
Anthony Newnam705c9442010-02-22 08:36:49 -0600735 if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800736 return 1;
737 } else {
738 END();
739 sync_quit(fd);
740 }
741 } else {
742 if(sync_readmode(fd, rpath, &mode)) {
743 return 1;
744 }
745 if((mode != 0) && S_ISDIR(mode)) {
746 /* if we're copying a local file to a remote directory,
747 ** we *really* want to copy to remotedir + "/" + localfilename
748 */
749 const char *name = adb_dirstop(lpath);
750 if(name == 0) {
751 name = lpath;
752 } else {
753 name++;
754 }
755 int tmplen = strlen(name) + strlen(rpath) + 2;
Dan Albertbac34742015-02-25 17:51:28 -0800756 char *tmp = reinterpret_cast<char*>(
757 malloc(strlen(name) + strlen(rpath) + 2));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800758 if(tmp == 0) return 1;
759 snprintf(tmp, tmplen, "%s/%s", rpath, name);
760 rpath = tmp;
761 }
762 BEGIN();
Jeff Sharkey960df972014-06-09 17:30:57 -0700763 if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800764 return 1;
765 } else {
766 END();
767 sync_quit(fd);
768 return 0;
769 }
770 }
771
772 return 0;
773}
774
775
Elliott Hughes2d4121c2015-04-17 09:47:42 -0700776struct sync_ls_build_list_cb_args {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800777 copyinfo **filelist;
778 copyinfo **dirlist;
779 const char *rpath;
780 const char *lpath;
Elliott Hughes2d4121c2015-04-17 09:47:42 -0700781};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800782
Elliott Hughes3edd54b2015-05-05 18:26:10 -0700783static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
784 const char* name, void* cookie)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800785{
786 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
787 copyinfo *ci;
788
789 if (S_ISDIR(mode)) {
790 copyinfo **dirlist = args->dirlist;
791
792 /* Don't try recursing down "." or ".." */
793 if (name[0] == '.') {
794 if (name[1] == '\0') return;
795 if ((name[1] == '.') && (name[2] == '\0')) return;
796 }
797
798 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
799 ci->next = *dirlist;
800 *dirlist = ci;
801 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
802 copyinfo **filelist = args->filelist;
803
804 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
805 ci->time = time;
806 ci->mode = mode;
807 ci->size = size;
808 ci->next = *filelist;
809 *filelist = ci;
810 } else {
811 fprintf(stderr, "skipping special file '%s'\n", name);
812 }
813}
814
815static int remote_build_list(int syncfd, copyinfo **filelist,
816 const char *rpath, const char *lpath)
817{
818 copyinfo *dirlist = NULL;
819 sync_ls_build_list_cb_args args;
820
821 args.filelist = filelist;
822 args.dirlist = &dirlist;
823 args.rpath = rpath;
824 args.lpath = lpath;
825
826 /* Put the files/dirs in rpath on the lists. */
827 if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
828 return 1;
829 }
830
831 /* Recurse into each directory we found. */
832 while (dirlist != NULL) {
833 copyinfo *next = dirlist->next;
834 if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
835 return 1;
836 }
837 free(dirlist);
838 dirlist = next;
839 }
840
841 return 0;
842}
843
Dan Albertbac34742015-02-25 17:51:28 -0800844static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700845{
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700846 struct utimbuf times = { time, time };
847 int r1 = utime(lpath, &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700848
849 /* use umask for permissions */
850 mode_t mask=umask(0000);
851 umask(mask);
852 int r2 = chmod(lpath, mode & ~mask);
853
854 return r1 ? : r2;
855}
856
Riley Andrews4d04d242014-12-12 13:12:36 -0800857/* Return a copy of the path string with / appended if needed */
858static char *add_slash_to_path(const char *path)
859{
860 if (path[strlen(path) - 1] != '/') {
861 size_t len = strlen(path) + 2;
Dan Albertbac34742015-02-25 17:51:28 -0800862 char *path_with_slash = reinterpret_cast<char*>(malloc(len));
Riley Andrews4d04d242014-12-12 13:12:36 -0800863 if (path_with_slash == NULL)
864 return NULL;
865 snprintf(path_with_slash, len, "%s/", path);
866 return path_with_slash;
867 } else {
868 return strdup(path);
869 }
870}
871
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800872static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700873 int copy_attrs)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800874{
875 copyinfo *filelist = 0;
876 copyinfo *ci, *next;
877 int pulled = 0;
878 int skipped = 0;
Riley Andrews4d04d242014-12-12 13:12:36 -0800879 char *rpath_clean = NULL;
880 char *lpath_clean = NULL;
881 int ret = 0;
882
883 if (rpath[0] == '\0' || lpath[0] == '\0') {
884 ret = -1;
885 goto finish;
886 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800887
888 /* Make sure that both directory paths end in a slash. */
Riley Andrews4d04d242014-12-12 13:12:36 -0800889 rpath_clean = add_slash_to_path(rpath);
890 if (!rpath_clean) {
891 ret = -1;
892 goto finish;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800893 }
Riley Andrews4d04d242014-12-12 13:12:36 -0800894 lpath_clean = add_slash_to_path(lpath);
895 if (!lpath_clean) {
896 ret = -1;
897 goto finish;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800898 }
899
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800900 /* Recursively build the list of files to copy. */
Riley Andrews4d04d242014-12-12 13:12:36 -0800901 fprintf(stderr, "pull: building file list...\n");
902 if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
903 ret = -1;
904 goto finish;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800905 }
906
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800907 for (ci = filelist; ci != 0; ci = next) {
908 next = ci->next;
909 if (ci->flag == 0) {
910 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Mark Lindner76f2a932014-03-11 17:55:59 -0700911 if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
Riley Andrews4d04d242014-12-12 13:12:36 -0800912 ret = -1;
913 goto finish;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800914 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700915
916 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Riley Andrews4d04d242014-12-12 13:12:36 -0800917 ret = -1;
918 goto finish;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700919 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800920 pulled++;
921 } else {
922 skipped++;
923 }
924 free(ci);
925 }
926
927 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
928 pulled, (pulled == 1) ? "" : "s",
929 skipped, (skipped == 1) ? "" : "s");
930
Riley Andrews4d04d242014-12-12 13:12:36 -0800931finish:
932 free(lpath_clean);
933 free(rpath_clean);
934 return ret;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800935}
936
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700937int 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 -0800938{
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700939 unsigned mode, time;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800940 struct stat st;
941
Elliott Hughes078f0fc2015-04-29 08:35:59 -0700942 std::string error;
943 int fd = adb_connect("sync:", &error);
944 if (fd < 0) {
945 fprintf(stderr,"error: %s\n", error.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800946 return 1;
947 }
948
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700949 if(sync_readtime(fd, rpath, &time, &mode)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800950 return 1;
951 }
952 if(mode == 0) {
953 fprintf(stderr,"remote object '%s' does not exist\n", rpath);
954 return 1;
955 }
956
Matt Fischer457d81c2010-01-04 16:18:50 -0600957 if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800958 if(stat(lpath, &st) == 0) {
959 if(S_ISDIR(st.st_mode)) {
960 /* if we're copying a remote file to a local directory,
961 ** we *really* want to copy to localdir + "/" + remotefilename
962 */
963 const char *name = adb_dirstop(rpath);
964 if(name == 0) {
965 name = rpath;
966 } else {
967 name++;
968 }
969 int tmplen = strlen(name) + strlen(lpath) + 2;
Dan Albertbac34742015-02-25 17:51:28 -0800970 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800971 if(tmp == 0) return 1;
972 snprintf(tmp, tmplen, "%s/%s", lpath, name);
973 lpath = tmp;
974 }
975 }
976 BEGIN();
Mark Lindner76f2a932014-03-11 17:55:59 -0700977 if (sync_recv(fd, rpath, lpath, show_progress)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800978 return 1;
979 } else {
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700980 if (copy_attrs && set_time_and_mode(lpath, time, mode))
981 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800982 END();
983 sync_quit(fd);
984 return 0;
985 }
986 } else if(S_ISDIR(mode)) {
987 BEGIN();
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700988 if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800989 return 1;
990 } else {
991 END();
992 sync_quit(fd);
993 return 0;
994 }
995 } else {
996 fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
997 return 1;
998 }
999}
1000
Elliott Hughesd236d072015-04-21 10:17:07 -07001001int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001002{
Elliott Hughesd236d072015-04-21 10:17:07 -07001003 fprintf(stderr, "syncing %s...\n", rpath.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001004
Elliott Hughes078f0fc2015-04-29 08:35:59 -07001005 std::string error;
1006 int fd = adb_connect("sync:", &error);
Elliott Hughesd236d072015-04-21 10:17:07 -07001007 if (fd < 0) {
Elliott Hughes078f0fc2015-04-29 08:35:59 -07001008 fprintf(stderr, "error: %s\n", error.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001009 return 1;
1010 }
1011
1012 BEGIN();
Elliott Hughesd236d072015-04-21 10:17:07 -07001013 if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001014 return 1;
1015 } else {
1016 END();
1017 sync_quit(fd);
1018 return 0;
1019 }
1020}