blob: 4ba730b29b696ef09247dec9140ce3c6101ec73b [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
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080082void sync_quit(int fd)
83{
84 syncmsg msg;
85
86 msg.req.id = ID_QUIT;
87 msg.req.namelen = 0;
88
Dan Albert66a91b02015-02-24 21:26:58 -080089 WriteFdExactly(fd, &msg.req, sizeof(msg.req));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080090}
91
92typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
93
94int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
95{
96 syncmsg msg;
97 char buf[257];
98 int len;
99
100 len = strlen(path);
101 if(len > 1024) goto fail;
102
103 msg.req.id = ID_LIST;
104 msg.req.namelen = htoll(len);
105
Dan Albert66a91b02015-02-24 21:26:58 -0800106 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
107 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800108 goto fail;
109 }
110
111 for(;;) {
Dan Albert66a91b02015-02-24 21:26:58 -0800112 if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800113 if(msg.dent.id == ID_DONE) return 0;
114 if(msg.dent.id != ID_DENT) break;
115
116 len = ltohl(msg.dent.namelen);
117 if(len > 256) break;
118
Dan Albert66a91b02015-02-24 21:26:58 -0800119 if(!ReadFdExactly(fd, buf, len)) break;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800120 buf[len] = 0;
121
122 func(ltohl(msg.dent.mode),
123 ltohl(msg.dent.size),
124 ltohl(msg.dent.time),
125 buf, cookie);
126 }
127
128fail:
129 adb_close(fd);
130 return -1;
131}
132
133typedef struct syncsendbuf syncsendbuf;
134
135struct syncsendbuf {
136 unsigned id;
137 unsigned size;
138 char data[SYNC_DATA_MAX];
139};
140
141static syncsendbuf send_buffer;
142
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700143int sync_readtime(int fd, const char *path, unsigned int *timestamp,
144 unsigned int *mode)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800145{
146 syncmsg msg;
147 int len = strlen(path);
148
149 msg.req.id = ID_STAT;
150 msg.req.namelen = htoll(len);
151
Dan Albert66a91b02015-02-24 21:26:58 -0800152 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
153 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800154 return -1;
155 }
156
Dan Albert66a91b02015-02-24 21:26:58 -0800157 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800158 return -1;
159 }
160
161 if(msg.stat.id != ID_STAT) {
162 return -1;
163 }
164
165 *timestamp = ltohl(msg.stat.time);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700166 *mode = ltohl(msg.stat.mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800167 return 0;
168}
169
170static int sync_start_readtime(int fd, const char *path)
171{
172 syncmsg msg;
173 int len = strlen(path);
174
175 msg.req.id = ID_STAT;
176 msg.req.namelen = htoll(len);
177
Dan Albert66a91b02015-02-24 21:26:58 -0800178 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
179 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800180 return -1;
181 }
182
183 return 0;
184}
185
186static int sync_finish_readtime(int fd, unsigned int *timestamp,
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200187 unsigned int *mode, unsigned int *size)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800188{
189 syncmsg msg;
190
Dan Albert66a91b02015-02-24 21:26:58 -0800191 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800192 return -1;
193
194 if(msg.stat.id != ID_STAT)
195 return -1;
196
197 *timestamp = ltohl(msg.stat.time);
198 *mode = ltohl(msg.stat.mode);
199 *size = ltohl(msg.stat.size);
200
201 return 0;
202}
203
204int sync_readmode(int fd, const char *path, unsigned *mode)
205{
206 syncmsg msg;
207 int len = strlen(path);
208
209 msg.req.id = ID_STAT;
210 msg.req.namelen = htoll(len);
211
Dan Albert66a91b02015-02-24 21:26:58 -0800212 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
213 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800214 return -1;
215 }
216
Dan Albert66a91b02015-02-24 21:26:58 -0800217 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800218 return -1;
219 }
220
221 if(msg.stat.id != ID_STAT) {
222 return -1;
223 }
224
225 *mode = ltohl(msg.stat.mode);
226 return 0;
227}
228
Mark Lindner9f9d1452014-03-11 17:55:59 -0700229static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800230{
231 int lfd, err = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700232 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800233
234 lfd = adb_open(path, O_RDONLY);
235 if(lfd < 0) {
236 fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
237 return -1;
238 }
239
Mark Lindner9f9d1452014-03-11 17:55:59 -0700240 if (show_progress) {
241 // Determine local file size.
242 struct stat st;
eric.yan466d3f42015-02-03 22:16:29 +0800243 if (stat(path, &st)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700244 fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
245 return -1;
246 }
247
248 size = st.st_size;
249 }
250
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800251 sbuf->id = ID_DATA;
252 for(;;) {
253 int ret;
254
255 ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
256 if(!ret)
257 break;
258
259 if(ret < 0) {
260 if(errno == EINTR)
261 continue;
262 fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
263 break;
264 }
265
266 sbuf->size = htoll(ret);
Dan Albert66a91b02015-02-24 21:26:58 -0800267 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800268 err = -1;
269 break;
270 }
271 total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700272
273 if (show_progress) {
274 print_transfer_progress(total_bytes, size);
275 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800276 }
277
278 adb_close(lfd);
279 return err;
280}
281
Mark Lindner9f9d1452014-03-11 17:55:59 -0700282static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
283 int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800284{
285 int err = 0;
286 int total = 0;
287
288 sbuf->id = ID_DATA;
289 while (total < size) {
290 int count = size - total;
291 if (count > SYNC_DATA_MAX) {
292 count = SYNC_DATA_MAX;
293 }
294
295 memcpy(sbuf->data, &file_buffer[total], count);
296 sbuf->size = htoll(count);
Dan Albert66a91b02015-02-24 21:26:58 -0800297 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800298 err = -1;
299 break;
300 }
301 total += count;
302 total_bytes += count;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700303
304 if (show_progress) {
305 print_transfer_progress(total, size);
306 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800307 }
308
309 return err;
310}
311
Elliott Hughes944e1d72015-01-12 14:26:36 -0800312#if defined(_WIN32)
313extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
314#else
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800315static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
316{
317 int len, ret;
318
319 len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
320 if(len < 0) {
321 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
322 return -1;
323 }
324 sbuf->data[len] = '\0';
325
326 sbuf->size = htoll(len + 1);
327 sbuf->id = ID_DATA;
328
Dan Albert66a91b02015-02-24 21:26:58 -0800329 ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800330 if(ret)
331 return -1;
332
333 total_bytes += len + 1;
334
335 return 0;
336}
337#endif
338
339static int sync_send(int fd, const char *lpath, const char *rpath,
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700340 unsigned mtime, mode_t mode, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800341{
342 syncmsg msg;
343 int len, r;
344 syncsendbuf *sbuf = &send_buffer;
345 char* file_buffer = NULL;
346 int size = 0;
347 char tmp[64];
348
349 len = strlen(rpath);
350 if(len > 1024) goto fail;
351
352 snprintf(tmp, sizeof(tmp), ",%d", mode);
353 r = strlen(tmp);
354
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800355 msg.req.id = ID_SEND;
356 msg.req.namelen = htoll(len + r);
357
Dan Albert66a91b02015-02-24 21:26:58 -0800358 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
359 !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800360 free(file_buffer);
361 goto fail;
362 }
363
364 if (file_buffer) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700365 write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800366 free(file_buffer);
367 } else if (S_ISREG(mode))
Mark Lindner9f9d1452014-03-11 17:55:59 -0700368 write_data_file(fd, lpath, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800369 else if (S_ISLNK(mode))
370 write_data_link(fd, lpath, sbuf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800371 else
372 goto fail;
373
374 msg.data.id = ID_DONE;
375 msg.data.size = htoll(mtime);
Dan Albert66a91b02015-02-24 21:26:58 -0800376 if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800377 goto fail;
378
Dan Albert66a91b02015-02-24 21:26:58 -0800379 if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800380 return -1;
381
382 if(msg.status.id != ID_OKAY) {
383 if(msg.status.id == ID_FAIL) {
384 len = ltohl(msg.status.msglen);
385 if(len > 256) len = 256;
Dan Albert66a91b02015-02-24 21:26:58 -0800386 if(!ReadFdExactly(fd, sbuf->data, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800387 return -1;
388 }
389 sbuf->data[len] = 0;
390 } else
391 strcpy(sbuf->data, "unknown reason");
392
393 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
394 return -1;
395 }
396
397 return 0;
398
399fail:
400 fprintf(stderr,"protocol failure\n");
401 adb_close(fd);
402 return -1;
403}
404
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700405static int mkdirs(const char *name)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800406{
407 int ret;
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700408 char *x = (char *)name + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800409
410 for(;;) {
411 x = adb_dirstart(x);
412 if(x == 0) return 0;
413 *x = 0;
414 ret = adb_mkdir(name, 0775);
415 *x = OS_PATH_SEPARATOR;
416 if((ret < 0) && (errno != EEXIST)) {
417 return ret;
418 }
419 x++;
420 }
421 return 0;
422}
423
Mark Lindner9f9d1452014-03-11 17:55:59 -0700424int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800425{
426 syncmsg msg;
427 int len;
428 int lfd = -1;
429 char *buffer = send_buffer.data;
430 unsigned id;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700431 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800432
433 len = strlen(rpath);
434 if(len > 1024) return -1;
435
Mark Lindner9f9d1452014-03-11 17:55:59 -0700436 if (show_progress) {
437 // Determine remote file size.
438 syncmsg stat_msg;
439 stat_msg.req.id = ID_STAT;
440 stat_msg.req.namelen = htoll(len);
441
Dan Albert66a91b02015-02-24 21:26:58 -0800442 if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
443 !WriteFdExactly(fd, rpath, len)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700444 return -1;
445 }
446
Dan Albert66a91b02015-02-24 21:26:58 -0800447 if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700448 return -1;
449 }
450
451 if (stat_msg.stat.id != ID_STAT) return -1;
452
453 size = ltohl(stat_msg.stat.size);
454 }
455
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800456 msg.req.id = ID_RECV;
457 msg.req.namelen = htoll(len);
Dan Albert66a91b02015-02-24 21:26:58 -0800458 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
459 !WriteFdExactly(fd, rpath, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800460 return -1;
461 }
462
Dan Albert66a91b02015-02-24 21:26:58 -0800463 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800464 return -1;
465 }
466 id = msg.data.id;
467
468 if((id == ID_DATA) || (id == ID_DONE)) {
469 adb_unlink(lpath);
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700470 mkdirs(lpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800471 lfd = adb_creat(lpath, 0644);
472 if(lfd < 0) {
473 fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
474 return -1;
475 }
476 goto handle_data;
477 } else {
478 goto remote_error;
479 }
480
481 for(;;) {
Dan Albert66a91b02015-02-24 21:26:58 -0800482 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800483 return -1;
484 }
485 id = msg.data.id;
486
487 handle_data:
488 len = ltohl(msg.data.size);
489 if(id == ID_DONE) break;
490 if(id != ID_DATA) goto remote_error;
491 if(len > SYNC_DATA_MAX) {
492 fprintf(stderr,"data overrun\n");
493 adb_close(lfd);
494 return -1;
495 }
496
Dan Albert66a91b02015-02-24 21:26:58 -0800497 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800498 adb_close(lfd);
499 return -1;
500 }
501
Dan Albert66a91b02015-02-24 21:26:58 -0800502 if(!WriteFdExactly(lfd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800503 fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
504 adb_close(lfd);
505 return -1;
506 }
507
508 total_bytes += len;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700509
510 if (show_progress) {
511 print_transfer_progress(total_bytes, size);
512 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800513 }
514
515 adb_close(lfd);
516 return 0;
517
518remote_error:
519 adb_close(lfd);
520 adb_unlink(lpath);
521
522 if(id == ID_FAIL) {
523 len = ltohl(msg.data.size);
524 if(len > 256) len = 256;
Dan Albert66a91b02015-02-24 21:26:58 -0800525 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800526 return -1;
527 }
528 buffer[len] = 0;
529 } else {
530 memcpy(buffer, &id, 4);
531 buffer[4] = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800532 }
533 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
534 return 0;
535}
536
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800537/* --- */
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800538static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
539 const char *name, void *cookie)
540{
541 printf("%08x %08x %08x %s\n", mode, size, time, name);
542}
543
544int do_sync_ls(const char *path)
545{
546 int fd = adb_connect("sync:");
547 if(fd < 0) {
548 fprintf(stderr,"error: %s\n", adb_error());
549 return 1;
550 }
551
552 if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
553 return 1;
554 } else {
555 sync_quit(fd);
556 return 0;
557 }
558}
559
560typedef struct copyinfo copyinfo;
561
562struct copyinfo
563{
564 copyinfo *next;
565 const char *src;
566 const char *dst;
567 unsigned int time;
568 unsigned int mode;
569 unsigned int size;
570 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800571};
572
573copyinfo *mkcopyinfo(const char *spath, const char *dpath,
574 const char *name, int isdir)
575{
576 int slen = strlen(spath);
577 int dlen = strlen(dpath);
578 int nlen = strlen(name);
579 int ssize = slen + nlen + 2;
580 int dsize = dlen + nlen + 2;
581
Dan Albertf30d73c2015-02-25 17:51:28 -0800582 copyinfo *ci = reinterpret_cast<copyinfo*>(
583 malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800584 if(ci == 0) {
585 fprintf(stderr,"out of memory\n");
586 abort();
587 }
588
589 ci->next = 0;
590 ci->time = 0;
591 ci->mode = 0;
592 ci->size = 0;
593 ci->flag = 0;
594 ci->src = (const char*)(ci + 1);
595 ci->dst = ci->src + ssize;
596 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
597 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
598
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800599 return ci;
600}
601
602
603static int local_build_list(copyinfo **filelist,
604 const char *lpath, const char *rpath)
605{
606 DIR *d;
607 struct dirent *de;
608 struct stat st;
609 copyinfo *dirlist = 0;
610 copyinfo *ci, *next;
611
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800612 d = opendir(lpath);
613 if(d == 0) {
614 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
615 return -1;
616 }
617
618 while((de = readdir(d))) {
619 char stat_path[PATH_MAX];
620 char *name = de->d_name;
621
622 if(name[0] == '.') {
623 if(name[1] == 0) continue;
624 if((name[1] == '.') && (name[2] == 0)) continue;
625 }
626
627 /*
628 * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
629 * always returns DT_UNKNOWN, so we just use stat() for all cases.
630 */
631 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
632 continue;
633 strcpy(stat_path, lpath);
634 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800635
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700636 if(!lstat(stat_path, &st)) {
637 if (S_ISDIR(st.st_mode)) {
638 ci = mkcopyinfo(lpath, rpath, name, 1);
639 ci->next = dirlist;
640 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800641 } else {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700642 ci = mkcopyinfo(lpath, rpath, name, 0);
643 if(lstat(ci->src, &st)) {
644 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
645 free(ci);
646 closedir(d);
647 return -1;
648 }
649 if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
650 fprintf(stderr, "skipping special file '%s'\n", ci->src);
651 free(ci);
652 } else {
653 ci->time = st.st_mtime;
654 ci->mode = st.st_mode;
655 ci->size = st.st_size;
656 ci->next = *filelist;
657 *filelist = ci;
658 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800659 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700660 } else {
661 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800662 }
663 }
664
665 closedir(d);
666
667 for(ci = dirlist; ci != 0; ci = next) {
668 next = ci->next;
669 local_build_list(filelist, ci->src, ci->dst);
670 free(ci);
671 }
672
673 return 0;
674}
675
676
Anthony Newnamdd2db142010-02-22 08:36:49 -0600677static 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 -0800678{
679 copyinfo *filelist = 0;
680 copyinfo *ci, *next;
681 int pushed = 0;
682 int skipped = 0;
683
684 if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
685 if(lpath[strlen(lpath) - 1] != '/') {
686 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800687 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800688 if(tmp == 0) return -1;
689 snprintf(tmp, tmplen, "%s/",lpath);
690 lpath = tmp;
691 }
692 if(rpath[strlen(rpath) - 1] != '/') {
693 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800694 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800695 if(tmp == 0) return -1;
696 snprintf(tmp, tmplen, "%s/",rpath);
697 rpath = tmp;
698 }
699
700 if(local_build_list(&filelist, lpath, rpath)) {
701 return -1;
702 }
703
704 if(checktimestamps){
705 for(ci = filelist; ci != 0; ci = ci->next) {
706 if(sync_start_readtime(fd, ci->dst)) {
707 return 1;
708 }
709 }
710 for(ci = filelist; ci != 0; ci = ci->next) {
711 unsigned int timestamp, mode, size;
712 if(sync_finish_readtime(fd, &timestamp, &mode, &size))
713 return 1;
714 if(size == ci->size) {
715 /* for links, we cannot update the atime/mtime */
716 if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
717 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
718 ci->flag = 1;
719 }
720 }
721 }
722 for(ci = filelist; ci != 0; ci = next) {
723 next = ci->next;
724 if(ci->flag == 0) {
Anthony Newnamdd2db142010-02-22 08:36:49 -0600725 fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
726 if(!listonly &&
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700727 sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
Mark Lindner9f9d1452014-03-11 17:55:59 -0700728 0 /* no show progress */)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800729 return 1;
730 }
731 pushed++;
732 } else {
733 skipped++;
734 }
735 free(ci);
736 }
737
738 fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
739 pushed, (pushed == 1) ? "" : "s",
740 skipped, (skipped == 1) ? "" : "s");
741
742 return 0;
743}
744
745
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700746int do_sync_push(const char *lpath, const char *rpath, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800747{
748 struct stat st;
749 unsigned mode;
750 int fd;
751
752 fd = adb_connect("sync:");
753 if(fd < 0) {
754 fprintf(stderr,"error: %s\n", adb_error());
755 return 1;
756 }
757
758 if(stat(lpath, &st)) {
759 fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
760 sync_quit(fd);
761 return 1;
762 }
763
764 if(S_ISDIR(st.st_mode)) {
765 BEGIN();
Anthony Newnamdd2db142010-02-22 08:36:49 -0600766 if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800767 return 1;
768 } else {
769 END();
770 sync_quit(fd);
771 }
772 } else {
773 if(sync_readmode(fd, rpath, &mode)) {
774 return 1;
775 }
776 if((mode != 0) && S_ISDIR(mode)) {
777 /* if we're copying a local file to a remote directory,
778 ** we *really* want to copy to remotedir + "/" + localfilename
779 */
780 const char *name = adb_dirstop(lpath);
781 if(name == 0) {
782 name = lpath;
783 } else {
784 name++;
785 }
786 int tmplen = strlen(name) + strlen(rpath) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800787 char *tmp = reinterpret_cast<char*>(
788 malloc(strlen(name) + strlen(rpath) + 2));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800789 if(tmp == 0) return 1;
790 snprintf(tmp, tmplen, "%s/%s", rpath, name);
791 rpath = tmp;
792 }
793 BEGIN();
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700794 if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800795 return 1;
796 } else {
797 END();
798 sync_quit(fd);
799 return 0;
800 }
801 }
802
803 return 0;
804}
805
806
807typedef struct {
808 copyinfo **filelist;
809 copyinfo **dirlist;
810 const char *rpath;
811 const char *lpath;
812} sync_ls_build_list_cb_args;
813
814void
815sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
816 const char *name, void *cookie)
817{
818 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
819 copyinfo *ci;
820
821 if (S_ISDIR(mode)) {
822 copyinfo **dirlist = args->dirlist;
823
824 /* Don't try recursing down "." or ".." */
825 if (name[0] == '.') {
826 if (name[1] == '\0') return;
827 if ((name[1] == '.') && (name[2] == '\0')) return;
828 }
829
830 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
831 ci->next = *dirlist;
832 *dirlist = ci;
833 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
834 copyinfo **filelist = args->filelist;
835
836 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
837 ci->time = time;
838 ci->mode = mode;
839 ci->size = size;
840 ci->next = *filelist;
841 *filelist = ci;
842 } else {
843 fprintf(stderr, "skipping special file '%s'\n", name);
844 }
845}
846
847static int remote_build_list(int syncfd, copyinfo **filelist,
848 const char *rpath, const char *lpath)
849{
850 copyinfo *dirlist = NULL;
851 sync_ls_build_list_cb_args args;
852
853 args.filelist = filelist;
854 args.dirlist = &dirlist;
855 args.rpath = rpath;
856 args.lpath = lpath;
857
858 /* Put the files/dirs in rpath on the lists. */
859 if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
860 return 1;
861 }
862
863 /* Recurse into each directory we found. */
864 while (dirlist != NULL) {
865 copyinfo *next = dirlist->next;
866 if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
867 return 1;
868 }
869 free(dirlist);
870 dirlist = next;
871 }
872
873 return 0;
874}
875
Dan Albertf30d73c2015-02-25 17:51:28 -0800876static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700877{
Greg Hackmann8b689142014-05-06 08:48:18 -0700878 struct utimbuf times = { time, time };
879 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700880
881 /* use umask for permissions */
882 mode_t mask=umask(0000);
883 umask(mask);
884 int r2 = chmod(lpath, mode & ~mask);
885
886 return r1 ? : r2;
887}
888
Riley Andrewsc736a942014-12-12 13:12:36 -0800889/* Return a copy of the path string with / appended if needed */
890static char *add_slash_to_path(const char *path)
891{
892 if (path[strlen(path) - 1] != '/') {
893 size_t len = strlen(path) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800894 char *path_with_slash = reinterpret_cast<char*>(malloc(len));
Riley Andrewsc736a942014-12-12 13:12:36 -0800895 if (path_with_slash == NULL)
896 return NULL;
897 snprintf(path_with_slash, len, "%s/", path);
898 return path_with_slash;
899 } else {
900 return strdup(path);
901 }
902}
903
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800904static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700905 int copy_attrs)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800906{
907 copyinfo *filelist = 0;
908 copyinfo *ci, *next;
909 int pulled = 0;
910 int skipped = 0;
Riley Andrewsc736a942014-12-12 13:12:36 -0800911 char *rpath_clean = NULL;
912 char *lpath_clean = NULL;
913 int ret = 0;
914
915 if (rpath[0] == '\0' || lpath[0] == '\0') {
916 ret = -1;
917 goto finish;
918 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800919
920 /* Make sure that both directory paths end in a slash. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800921 rpath_clean = add_slash_to_path(rpath);
922 if (!rpath_clean) {
923 ret = -1;
924 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800925 }
Riley Andrewsc736a942014-12-12 13:12:36 -0800926 lpath_clean = add_slash_to_path(lpath);
927 if (!lpath_clean) {
928 ret = -1;
929 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800930 }
931
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800932 /* Recursively build the list of files to copy. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800933 fprintf(stderr, "pull: building file list...\n");
934 if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
935 ret = -1;
936 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800937 }
938
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800939 for (ci = filelist; ci != 0; ci = next) {
940 next = ci->next;
941 if (ci->flag == 0) {
942 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700943 if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800944 ret = -1;
945 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800946 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700947
948 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800949 ret = -1;
950 goto finish;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700951 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800952 pulled++;
953 } else {
954 skipped++;
955 }
956 free(ci);
957 }
958
959 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
960 pulled, (pulled == 1) ? "" : "s",
961 skipped, (skipped == 1) ? "" : "s");
962
Riley Andrewsc736a942014-12-12 13:12:36 -0800963finish:
964 free(lpath_clean);
965 free(rpath_clean);
966 return ret;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800967}
968
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700969int 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 -0800970{
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700971 unsigned mode, time;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800972 struct stat st;
973
974 int fd;
975
976 fd = adb_connect("sync:");
977 if(fd < 0) {
978 fprintf(stderr,"error: %s\n", adb_error());
979 return 1;
980 }
981
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700982 if(sync_readtime(fd, rpath, &time, &mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800983 return 1;
984 }
985 if(mode == 0) {
986 fprintf(stderr,"remote object '%s' does not exist\n", rpath);
987 return 1;
988 }
989
Matt Fischer3ba90752010-01-04 16:18:50 -0600990 if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800991 if(stat(lpath, &st) == 0) {
992 if(S_ISDIR(st.st_mode)) {
993 /* if we're copying a remote file to a local directory,
994 ** we *really* want to copy to localdir + "/" + remotefilename
995 */
996 const char *name = adb_dirstop(rpath);
997 if(name == 0) {
998 name = rpath;
999 } else {
1000 name++;
1001 }
1002 int tmplen = strlen(name) + strlen(lpath) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -08001003 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001004 if(tmp == 0) return 1;
1005 snprintf(tmp, tmplen, "%s/%s", lpath, name);
1006 lpath = tmp;
1007 }
1008 }
1009 BEGIN();
Mark Lindner9f9d1452014-03-11 17:55:59 -07001010 if (sync_recv(fd, rpath, lpath, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001011 return 1;
1012 } else {
Lajos Molnar4e23e3c2013-04-19 12:41:09 -07001013 if (copy_attrs && set_time_and_mode(lpath, time, mode))
1014 return 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001015 END();
1016 sync_quit(fd);
1017 return 0;
1018 }
1019 } else if(S_ISDIR(mode)) {
1020 BEGIN();
Lajos Molnar4e23e3c2013-04-19 12:41:09 -07001021 if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001022 return 1;
1023 } else {
1024 END();
1025 sync_quit(fd);
1026 return 0;
1027 }
1028 } else {
1029 fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
1030 return 1;
1031 }
1032}
1033
Anthony Newnamdd2db142010-02-22 08:36:49 -06001034int do_sync_sync(const char *lpath, const char *rpath, int listonly)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001035{
1036 fprintf(stderr,"syncing %s...\n",rpath);
1037
1038 int fd = adb_connect("sync:");
1039 if(fd < 0) {
1040 fprintf(stderr,"error: %s\n", adb_error());
1041 return 1;
1042 }
1043
1044 BEGIN();
Anthony Newnamdd2db142010-02-22 08:36:49 -06001045 if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001046 return 1;
1047 } else {
1048 END();
1049 sync_quit(fd);
1050 return 0;
1051 }
1052}