blob: 730a5e24321a71a07ab80b11c4728b029a7d8e4f [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
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800133struct syncsendbuf {
134 unsigned id;
135 unsigned size;
136 char data[SYNC_DATA_MAX];
137};
138
139static syncsendbuf send_buffer;
140
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700141int sync_readtime(int fd, const char *path, unsigned int *timestamp,
142 unsigned int *mode)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800143{
144 syncmsg msg;
145 int len = strlen(path);
146
147 msg.req.id = ID_STAT;
148 msg.req.namelen = htoll(len);
149
Dan Albert66a91b02015-02-24 21:26:58 -0800150 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
151 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800152 return -1;
153 }
154
Dan Albert66a91b02015-02-24 21:26:58 -0800155 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800156 return -1;
157 }
158
159 if(msg.stat.id != ID_STAT) {
160 return -1;
161 }
162
163 *timestamp = ltohl(msg.stat.time);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700164 *mode = ltohl(msg.stat.mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800165 return 0;
166}
167
168static int sync_start_readtime(int fd, const char *path)
169{
170 syncmsg msg;
171 int len = strlen(path);
172
173 msg.req.id = ID_STAT;
174 msg.req.namelen = htoll(len);
175
Dan Albert66a91b02015-02-24 21:26:58 -0800176 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
177 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800178 return -1;
179 }
180
181 return 0;
182}
183
184static int sync_finish_readtime(int fd, unsigned int *timestamp,
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200185 unsigned int *mode, unsigned int *size)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800186{
187 syncmsg msg;
188
Dan Albert66a91b02015-02-24 21:26:58 -0800189 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800190 return -1;
191
192 if(msg.stat.id != ID_STAT)
193 return -1;
194
195 *timestamp = ltohl(msg.stat.time);
196 *mode = ltohl(msg.stat.mode);
197 *size = ltohl(msg.stat.size);
198
199 return 0;
200}
201
202int sync_readmode(int fd, const char *path, unsigned *mode)
203{
204 syncmsg msg;
205 int len = strlen(path);
206
207 msg.req.id = ID_STAT;
208 msg.req.namelen = htoll(len);
209
Dan Albert66a91b02015-02-24 21:26:58 -0800210 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
211 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800212 return -1;
213 }
214
Dan Albert66a91b02015-02-24 21:26:58 -0800215 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800216 return -1;
217 }
218
219 if(msg.stat.id != ID_STAT) {
220 return -1;
221 }
222
223 *mode = ltohl(msg.stat.mode);
224 return 0;
225}
226
Mark Lindner9f9d1452014-03-11 17:55:59 -0700227static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800228{
229 int lfd, err = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700230 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800231
232 lfd = adb_open(path, O_RDONLY);
233 if(lfd < 0) {
234 fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
235 return -1;
236 }
237
Mark Lindner9f9d1452014-03-11 17:55:59 -0700238 if (show_progress) {
239 // Determine local file size.
240 struct stat st;
eric.yan466d3f42015-02-03 22:16:29 +0800241 if (stat(path, &st)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700242 fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
243 return -1;
244 }
245
246 size = st.st_size;
247 }
248
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800249 sbuf->id = ID_DATA;
250 for(;;) {
251 int ret;
252
253 ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
254 if(!ret)
255 break;
256
257 if(ret < 0) {
258 if(errno == EINTR)
259 continue;
260 fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
261 break;
262 }
263
264 sbuf->size = htoll(ret);
Dan Albert66a91b02015-02-24 21:26:58 -0800265 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800266 err = -1;
267 break;
268 }
269 total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700270
271 if (show_progress) {
272 print_transfer_progress(total_bytes, size);
273 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800274 }
275
276 adb_close(lfd);
277 return err;
278}
279
Mark Lindner9f9d1452014-03-11 17:55:59 -0700280static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
281 int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800282{
283 int err = 0;
284 int total = 0;
285
286 sbuf->id = ID_DATA;
287 while (total < size) {
288 int count = size - total;
289 if (count > SYNC_DATA_MAX) {
290 count = SYNC_DATA_MAX;
291 }
292
293 memcpy(sbuf->data, &file_buffer[total], count);
294 sbuf->size = htoll(count);
Dan Albert66a91b02015-02-24 21:26:58 -0800295 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800296 err = -1;
297 break;
298 }
299 total += count;
300 total_bytes += count;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700301
302 if (show_progress) {
303 print_transfer_progress(total, size);
304 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800305 }
306
307 return err;
308}
309
Elliott Hughes944e1d72015-01-12 14:26:36 -0800310#if defined(_WIN32)
311extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
312#else
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800313static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
314{
315 int len, ret;
316
317 len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
318 if(len < 0) {
319 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
320 return -1;
321 }
322 sbuf->data[len] = '\0';
323
324 sbuf->size = htoll(len + 1);
325 sbuf->id = ID_DATA;
326
Dan Albert66a91b02015-02-24 21:26:58 -0800327 ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800328 if(ret)
329 return -1;
330
331 total_bytes += len + 1;
332
333 return 0;
334}
335#endif
336
337static int sync_send(int fd, const char *lpath, const char *rpath,
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700338 unsigned mtime, mode_t mode, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800339{
340 syncmsg msg;
341 int len, r;
342 syncsendbuf *sbuf = &send_buffer;
343 char* file_buffer = NULL;
344 int size = 0;
345 char tmp[64];
346
347 len = strlen(rpath);
348 if(len > 1024) goto fail;
349
350 snprintf(tmp, sizeof(tmp), ",%d", mode);
351 r = strlen(tmp);
352
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800353 msg.req.id = ID_SEND;
354 msg.req.namelen = htoll(len + r);
355
Dan Albert66a91b02015-02-24 21:26:58 -0800356 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
357 !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800358 free(file_buffer);
359 goto fail;
360 }
361
362 if (file_buffer) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700363 write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800364 free(file_buffer);
365 } else if (S_ISREG(mode))
Mark Lindner9f9d1452014-03-11 17:55:59 -0700366 write_data_file(fd, lpath, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800367 else if (S_ISLNK(mode))
368 write_data_link(fd, lpath, sbuf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800369 else
370 goto fail;
371
372 msg.data.id = ID_DONE;
373 msg.data.size = htoll(mtime);
Dan Albert66a91b02015-02-24 21:26:58 -0800374 if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800375 goto fail;
376
Dan Albert66a91b02015-02-24 21:26:58 -0800377 if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800378 return -1;
379
380 if(msg.status.id != ID_OKAY) {
381 if(msg.status.id == ID_FAIL) {
382 len = ltohl(msg.status.msglen);
383 if(len > 256) len = 256;
Dan Albert66a91b02015-02-24 21:26:58 -0800384 if(!ReadFdExactly(fd, sbuf->data, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800385 return -1;
386 }
387 sbuf->data[len] = 0;
388 } else
389 strcpy(sbuf->data, "unknown reason");
390
391 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
392 return -1;
393 }
394
395 return 0;
396
397fail:
398 fprintf(stderr,"protocol failure\n");
399 adb_close(fd);
400 return -1;
401}
402
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700403static int mkdirs(const char *name)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800404{
405 int ret;
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700406 char *x = (char *)name + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800407
408 for(;;) {
409 x = adb_dirstart(x);
410 if(x == 0) return 0;
411 *x = 0;
412 ret = adb_mkdir(name, 0775);
413 *x = OS_PATH_SEPARATOR;
414 if((ret < 0) && (errno != EEXIST)) {
415 return ret;
416 }
417 x++;
418 }
419 return 0;
420}
421
Mark Lindner9f9d1452014-03-11 17:55:59 -0700422int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800423{
424 syncmsg msg;
425 int len;
426 int lfd = -1;
427 char *buffer = send_buffer.data;
428 unsigned id;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700429 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800430
431 len = strlen(rpath);
432 if(len > 1024) return -1;
433
Mark Lindner9f9d1452014-03-11 17:55:59 -0700434 if (show_progress) {
435 // Determine remote file size.
436 syncmsg stat_msg;
437 stat_msg.req.id = ID_STAT;
438 stat_msg.req.namelen = htoll(len);
439
Dan Albert66a91b02015-02-24 21:26:58 -0800440 if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
441 !WriteFdExactly(fd, rpath, len)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700442 return -1;
443 }
444
Dan Albert66a91b02015-02-24 21:26:58 -0800445 if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700446 return -1;
447 }
448
449 if (stat_msg.stat.id != ID_STAT) return -1;
450
451 size = ltohl(stat_msg.stat.size);
452 }
453
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800454 msg.req.id = ID_RECV;
455 msg.req.namelen = htoll(len);
Dan Albert66a91b02015-02-24 21:26:58 -0800456 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
457 !WriteFdExactly(fd, rpath, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800458 return -1;
459 }
460
Dan Albert66a91b02015-02-24 21:26:58 -0800461 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800462 return -1;
463 }
464 id = msg.data.id;
465
466 if((id == ID_DATA) || (id == ID_DONE)) {
467 adb_unlink(lpath);
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700468 mkdirs(lpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800469 lfd = adb_creat(lpath, 0644);
470 if(lfd < 0) {
471 fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
472 return -1;
473 }
474 goto handle_data;
475 } else {
476 goto remote_error;
477 }
478
479 for(;;) {
Dan Albert66a91b02015-02-24 21:26:58 -0800480 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800481 return -1;
482 }
483 id = msg.data.id;
484
485 handle_data:
486 len = ltohl(msg.data.size);
487 if(id == ID_DONE) break;
488 if(id != ID_DATA) goto remote_error;
489 if(len > SYNC_DATA_MAX) {
490 fprintf(stderr,"data overrun\n");
491 adb_close(lfd);
492 return -1;
493 }
494
Dan Albert66a91b02015-02-24 21:26:58 -0800495 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800496 adb_close(lfd);
497 return -1;
498 }
499
Dan Albert66a91b02015-02-24 21:26:58 -0800500 if(!WriteFdExactly(lfd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800501 fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
502 adb_close(lfd);
503 return -1;
504 }
505
506 total_bytes += len;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700507
508 if (show_progress) {
509 print_transfer_progress(total_bytes, size);
510 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800511 }
512
513 adb_close(lfd);
514 return 0;
515
516remote_error:
517 adb_close(lfd);
518 adb_unlink(lpath);
519
520 if(id == ID_FAIL) {
521 len = ltohl(msg.data.size);
522 if(len > 256) len = 256;
Dan Albert66a91b02015-02-24 21:26:58 -0800523 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800524 return -1;
525 }
526 buffer[len] = 0;
527 } else {
528 memcpy(buffer, &id, 4);
529 buffer[4] = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800530 }
531 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
532 return 0;
533}
534
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800535/* --- */
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800536static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
537 const char *name, void *cookie)
538{
539 printf("%08x %08x %08x %s\n", mode, size, time, name);
540}
541
542int do_sync_ls(const char *path)
543{
544 int fd = adb_connect("sync:");
545 if(fd < 0) {
546 fprintf(stderr,"error: %s\n", adb_error());
547 return 1;
548 }
549
550 if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
551 return 1;
552 } else {
553 sync_quit(fd);
554 return 0;
555 }
556}
557
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800558struct copyinfo
559{
560 copyinfo *next;
561 const char *src;
562 const char *dst;
563 unsigned int time;
564 unsigned int mode;
565 unsigned int size;
566 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800567};
568
569copyinfo *mkcopyinfo(const char *spath, const char *dpath,
570 const char *name, int isdir)
571{
572 int slen = strlen(spath);
573 int dlen = strlen(dpath);
574 int nlen = strlen(name);
575 int ssize = slen + nlen + 2;
576 int dsize = dlen + nlen + 2;
577
Dan Albertf30d73c2015-02-25 17:51:28 -0800578 copyinfo *ci = reinterpret_cast<copyinfo*>(
579 malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800580 if(ci == 0) {
581 fprintf(stderr,"out of memory\n");
582 abort();
583 }
584
585 ci->next = 0;
586 ci->time = 0;
587 ci->mode = 0;
588 ci->size = 0;
589 ci->flag = 0;
590 ci->src = (const char*)(ci + 1);
591 ci->dst = ci->src + ssize;
592 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
593 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
594
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800595 return ci;
596}
597
598
599static int local_build_list(copyinfo **filelist,
600 const char *lpath, const char *rpath)
601{
602 DIR *d;
603 struct dirent *de;
604 struct stat st;
605 copyinfo *dirlist = 0;
606 copyinfo *ci, *next;
607
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800608 d = opendir(lpath);
609 if(d == 0) {
610 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
611 return -1;
612 }
613
614 while((de = readdir(d))) {
615 char stat_path[PATH_MAX];
616 char *name = de->d_name;
617
618 if(name[0] == '.') {
619 if(name[1] == 0) continue;
620 if((name[1] == '.') && (name[2] == 0)) continue;
621 }
622
623 /*
624 * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
625 * always returns DT_UNKNOWN, so we just use stat() for all cases.
626 */
627 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
628 continue;
629 strcpy(stat_path, lpath);
630 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800631
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700632 if(!lstat(stat_path, &st)) {
633 if (S_ISDIR(st.st_mode)) {
634 ci = mkcopyinfo(lpath, rpath, name, 1);
635 ci->next = dirlist;
636 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800637 } else {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700638 ci = mkcopyinfo(lpath, rpath, name, 0);
639 if(lstat(ci->src, &st)) {
640 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
641 free(ci);
642 closedir(d);
643 return -1;
644 }
645 if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
646 fprintf(stderr, "skipping special file '%s'\n", ci->src);
647 free(ci);
648 } else {
649 ci->time = st.st_mtime;
650 ci->mode = st.st_mode;
651 ci->size = st.st_size;
652 ci->next = *filelist;
653 *filelist = ci;
654 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800655 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700656 } else {
657 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800658 }
659 }
660
661 closedir(d);
662
663 for(ci = dirlist; ci != 0; ci = next) {
664 next = ci->next;
665 local_build_list(filelist, ci->src, ci->dst);
666 free(ci);
667 }
668
669 return 0;
670}
671
672
Anthony Newnamdd2db142010-02-22 08:36:49 -0600673static 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 -0800674{
675 copyinfo *filelist = 0;
676 copyinfo *ci, *next;
677 int pushed = 0;
678 int skipped = 0;
679
680 if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
681 if(lpath[strlen(lpath) - 1] != '/') {
682 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800683 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800684 if(tmp == 0) return -1;
685 snprintf(tmp, tmplen, "%s/",lpath);
686 lpath = tmp;
687 }
688 if(rpath[strlen(rpath) - 1] != '/') {
689 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800690 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800691 if(tmp == 0) return -1;
692 snprintf(tmp, tmplen, "%s/",rpath);
693 rpath = tmp;
694 }
695
696 if(local_build_list(&filelist, lpath, rpath)) {
697 return -1;
698 }
699
700 if(checktimestamps){
701 for(ci = filelist; ci != 0; ci = ci->next) {
702 if(sync_start_readtime(fd, ci->dst)) {
703 return 1;
704 }
705 }
706 for(ci = filelist; ci != 0; ci = ci->next) {
707 unsigned int timestamp, mode, size;
708 if(sync_finish_readtime(fd, &timestamp, &mode, &size))
709 return 1;
710 if(size == ci->size) {
711 /* for links, we cannot update the atime/mtime */
712 if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
713 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
714 ci->flag = 1;
715 }
716 }
717 }
718 for(ci = filelist; ci != 0; ci = next) {
719 next = ci->next;
720 if(ci->flag == 0) {
Anthony Newnamdd2db142010-02-22 08:36:49 -0600721 fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
722 if(!listonly &&
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700723 sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
Mark Lindner9f9d1452014-03-11 17:55:59 -0700724 0 /* no show progress */)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800725 return 1;
726 }
727 pushed++;
728 } else {
729 skipped++;
730 }
731 free(ci);
732 }
733
734 fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
735 pushed, (pushed == 1) ? "" : "s",
736 skipped, (skipped == 1) ? "" : "s");
737
738 return 0;
739}
740
741
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700742int do_sync_push(const char *lpath, const char *rpath, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800743{
744 struct stat st;
745 unsigned mode;
746 int fd;
747
748 fd = adb_connect("sync:");
749 if(fd < 0) {
750 fprintf(stderr,"error: %s\n", adb_error());
751 return 1;
752 }
753
754 if(stat(lpath, &st)) {
755 fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
756 sync_quit(fd);
757 return 1;
758 }
759
760 if(S_ISDIR(st.st_mode)) {
761 BEGIN();
Anthony Newnamdd2db142010-02-22 08:36:49 -0600762 if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800763 return 1;
764 } else {
765 END();
766 sync_quit(fd);
767 }
768 } else {
769 if(sync_readmode(fd, rpath, &mode)) {
770 return 1;
771 }
772 if((mode != 0) && S_ISDIR(mode)) {
773 /* if we're copying a local file to a remote directory,
774 ** we *really* want to copy to remotedir + "/" + localfilename
775 */
776 const char *name = adb_dirstop(lpath);
777 if(name == 0) {
778 name = lpath;
779 } else {
780 name++;
781 }
782 int tmplen = strlen(name) + strlen(rpath) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800783 char *tmp = reinterpret_cast<char*>(
784 malloc(strlen(name) + strlen(rpath) + 2));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800785 if(tmp == 0) return 1;
786 snprintf(tmp, tmplen, "%s/%s", rpath, name);
787 rpath = tmp;
788 }
789 BEGIN();
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700790 if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800791 return 1;
792 } else {
793 END();
794 sync_quit(fd);
795 return 0;
796 }
797 }
798
799 return 0;
800}
801
802
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700803struct sync_ls_build_list_cb_args {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800804 copyinfo **filelist;
805 copyinfo **dirlist;
806 const char *rpath;
807 const char *lpath;
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700808};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800809
810void
811sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
812 const char *name, void *cookie)
813{
814 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
815 copyinfo *ci;
816
817 if (S_ISDIR(mode)) {
818 copyinfo **dirlist = args->dirlist;
819
820 /* Don't try recursing down "." or ".." */
821 if (name[0] == '.') {
822 if (name[1] == '\0') return;
823 if ((name[1] == '.') && (name[2] == '\0')) return;
824 }
825
826 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
827 ci->next = *dirlist;
828 *dirlist = ci;
829 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
830 copyinfo **filelist = args->filelist;
831
832 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
833 ci->time = time;
834 ci->mode = mode;
835 ci->size = size;
836 ci->next = *filelist;
837 *filelist = ci;
838 } else {
839 fprintf(stderr, "skipping special file '%s'\n", name);
840 }
841}
842
843static int remote_build_list(int syncfd, copyinfo **filelist,
844 const char *rpath, const char *lpath)
845{
846 copyinfo *dirlist = NULL;
847 sync_ls_build_list_cb_args args;
848
849 args.filelist = filelist;
850 args.dirlist = &dirlist;
851 args.rpath = rpath;
852 args.lpath = lpath;
853
854 /* Put the files/dirs in rpath on the lists. */
855 if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
856 return 1;
857 }
858
859 /* Recurse into each directory we found. */
860 while (dirlist != NULL) {
861 copyinfo *next = dirlist->next;
862 if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
863 return 1;
864 }
865 free(dirlist);
866 dirlist = next;
867 }
868
869 return 0;
870}
871
Dan Albertf30d73c2015-02-25 17:51:28 -0800872static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700873{
Greg Hackmann8b689142014-05-06 08:48:18 -0700874 struct utimbuf times = { time, time };
875 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700876
877 /* use umask for permissions */
878 mode_t mask=umask(0000);
879 umask(mask);
880 int r2 = chmod(lpath, mode & ~mask);
881
882 return r1 ? : r2;
883}
884
Riley Andrewsc736a942014-12-12 13:12:36 -0800885/* Return a copy of the path string with / appended if needed */
886static char *add_slash_to_path(const char *path)
887{
888 if (path[strlen(path) - 1] != '/') {
889 size_t len = strlen(path) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800890 char *path_with_slash = reinterpret_cast<char*>(malloc(len));
Riley Andrewsc736a942014-12-12 13:12:36 -0800891 if (path_with_slash == NULL)
892 return NULL;
893 snprintf(path_with_slash, len, "%s/", path);
894 return path_with_slash;
895 } else {
896 return strdup(path);
897 }
898}
899
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800900static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700901 int copy_attrs)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800902{
903 copyinfo *filelist = 0;
904 copyinfo *ci, *next;
905 int pulled = 0;
906 int skipped = 0;
Riley Andrewsc736a942014-12-12 13:12:36 -0800907 char *rpath_clean = NULL;
908 char *lpath_clean = NULL;
909 int ret = 0;
910
911 if (rpath[0] == '\0' || lpath[0] == '\0') {
912 ret = -1;
913 goto finish;
914 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800915
916 /* Make sure that both directory paths end in a slash. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800917 rpath_clean = add_slash_to_path(rpath);
918 if (!rpath_clean) {
919 ret = -1;
920 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800921 }
Riley Andrewsc736a942014-12-12 13:12:36 -0800922 lpath_clean = add_slash_to_path(lpath);
923 if (!lpath_clean) {
924 ret = -1;
925 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800926 }
927
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800928 /* Recursively build the list of files to copy. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800929 fprintf(stderr, "pull: building file list...\n");
930 if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
931 ret = -1;
932 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800933 }
934
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800935 for (ci = filelist; ci != 0; ci = next) {
936 next = ci->next;
937 if (ci->flag == 0) {
938 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700939 if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800940 ret = -1;
941 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800942 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700943
944 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800945 ret = -1;
946 goto finish;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700947 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800948 pulled++;
949 } else {
950 skipped++;
951 }
952 free(ci);
953 }
954
955 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
956 pulled, (pulled == 1) ? "" : "s",
957 skipped, (skipped == 1) ? "" : "s");
958
Riley Andrewsc736a942014-12-12 13:12:36 -0800959finish:
960 free(lpath_clean);
961 free(rpath_clean);
962 return ret;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800963}
964
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700965int 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 -0800966{
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700967 unsigned mode, time;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800968 struct stat st;
969
970 int fd;
971
972 fd = adb_connect("sync:");
973 if(fd < 0) {
974 fprintf(stderr,"error: %s\n", adb_error());
975 return 1;
976 }
977
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700978 if(sync_readtime(fd, rpath, &time, &mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800979 return 1;
980 }
981 if(mode == 0) {
982 fprintf(stderr,"remote object '%s' does not exist\n", rpath);
983 return 1;
984 }
985
Matt Fischer3ba90752010-01-04 16:18:50 -0600986 if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800987 if(stat(lpath, &st) == 0) {
988 if(S_ISDIR(st.st_mode)) {
989 /* if we're copying a remote file to a local directory,
990 ** we *really* want to copy to localdir + "/" + remotefilename
991 */
992 const char *name = adb_dirstop(rpath);
993 if(name == 0) {
994 name = rpath;
995 } else {
996 name++;
997 }
998 int tmplen = strlen(name) + strlen(lpath) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800999 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001000 if(tmp == 0) return 1;
1001 snprintf(tmp, tmplen, "%s/%s", lpath, name);
1002 lpath = tmp;
1003 }
1004 }
1005 BEGIN();
Mark Lindner9f9d1452014-03-11 17:55:59 -07001006 if (sync_recv(fd, rpath, lpath, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001007 return 1;
1008 } else {
Lajos Molnar4e23e3c2013-04-19 12:41:09 -07001009 if (copy_attrs && set_time_and_mode(lpath, time, mode))
1010 return 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001011 END();
1012 sync_quit(fd);
1013 return 0;
1014 }
1015 } else if(S_ISDIR(mode)) {
1016 BEGIN();
Lajos Molnar4e23e3c2013-04-19 12:41:09 -07001017 if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001018 return 1;
1019 } else {
1020 END();
1021 sync_quit(fd);
1022 return 0;
1023 }
1024 } else {
1025 fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
1026 return 1;
1027 }
1028}
1029
Anthony Newnamdd2db142010-02-22 08:36:49 -06001030int do_sync_sync(const char *lpath, const char *rpath, int listonly)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001031{
1032 fprintf(stderr,"syncing %s...\n",rpath);
1033
1034 int fd = adb_connect("sync:");
1035 if(fd < 0) {
1036 fprintf(stderr,"error: %s\n", adb_error());
1037 return 1;
1038 }
1039
1040 BEGIN();
Anthony Newnamdd2db142010-02-22 08:36:49 -06001041 if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001042 return 1;
1043 } else {
1044 END();
1045 sync_quit(fd);
1046 return 0;
1047 }
1048}