blob: 8ce4ee28eed2536b9501b76d45f16eb14518182f [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"
Dan Albertb302d122015-02-24 15:51:19 -080035#include "zipfile/zipfile.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080036
Jeff Smith51d3fc12013-06-15 15:32:05 -050037static unsigned long long total_bytes;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080038static long long start_time;
39
40static long long NOW()
41{
42 struct timeval tv;
43 gettimeofday(&tv, 0);
44 return ((long long) tv.tv_usec) +
45 1000000LL * ((long long) tv.tv_sec);
46}
47
48static void BEGIN()
49{
50 total_bytes = 0;
51 start_time = NOW();
52}
53
54static void END()
55{
56 long long t = NOW() - start_time;
57 if(total_bytes == 0) return;
58
59 if (t == 0) /* prevent division by 0 :-) */
60 t = 1000000;
61
Mike Lockwoodeaf5a1e2010-12-14 23:07:32 -080062 fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
Jeff Smith51d3fc12013-06-15 15:32:05 -050063 ((total_bytes * 1000000LL) / t) / 1024LL,
64 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080065}
66
Mark Lindner9f9d1452014-03-11 17:55:59 -070067static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)";
68
69static void print_transfer_progress(unsigned long long bytes_current,
70 unsigned long long bytes_total) {
71 if (bytes_total == 0) return;
72
73 fprintf(stderr, transfer_progress_format, bytes_current, bytes_total,
74 (int) (bytes_current * 100 / bytes_total));
75
76 if (bytes_current == bytes_total) {
77 fputc('\n', stderr);
78 }
79
80 fflush(stderr);
81}
82
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080083void sync_quit(int fd)
84{
85 syncmsg msg;
86
87 msg.req.id = ID_QUIT;
88 msg.req.namelen = 0;
89
Dan Albert66a91b02015-02-24 21:26:58 -080090 WriteFdExactly(fd, &msg.req, sizeof(msg.req));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080091}
92
93typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
94
95int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
96{
97 syncmsg msg;
98 char buf[257];
99 int len;
100
101 len = strlen(path);
102 if(len > 1024) goto fail;
103
104 msg.req.id = ID_LIST;
105 msg.req.namelen = htoll(len);
106
Dan Albert66a91b02015-02-24 21:26:58 -0800107 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
108 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800109 goto fail;
110 }
111
112 for(;;) {
Dan Albert66a91b02015-02-24 21:26:58 -0800113 if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800114 if(msg.dent.id == ID_DONE) return 0;
115 if(msg.dent.id != ID_DENT) break;
116
117 len = ltohl(msg.dent.namelen);
118 if(len > 256) break;
119
Dan Albert66a91b02015-02-24 21:26:58 -0800120 if(!ReadFdExactly(fd, buf, len)) break;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800121 buf[len] = 0;
122
123 func(ltohl(msg.dent.mode),
124 ltohl(msg.dent.size),
125 ltohl(msg.dent.time),
126 buf, cookie);
127 }
128
129fail:
130 adb_close(fd);
131 return -1;
132}
133
134typedef struct syncsendbuf syncsendbuf;
135
136struct syncsendbuf {
137 unsigned id;
138 unsigned size;
139 char data[SYNC_DATA_MAX];
140};
141
142static syncsendbuf send_buffer;
143
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700144int sync_readtime(int fd, const char *path, unsigned int *timestamp,
145 unsigned int *mode)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800146{
147 syncmsg msg;
148 int len = strlen(path);
149
150 msg.req.id = ID_STAT;
151 msg.req.namelen = htoll(len);
152
Dan Albert66a91b02015-02-24 21:26:58 -0800153 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
154 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800155 return -1;
156 }
157
Dan Albert66a91b02015-02-24 21:26:58 -0800158 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800159 return -1;
160 }
161
162 if(msg.stat.id != ID_STAT) {
163 return -1;
164 }
165
166 *timestamp = ltohl(msg.stat.time);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700167 *mode = ltohl(msg.stat.mode);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800168 return 0;
169}
170
171static int sync_start_readtime(int fd, const char *path)
172{
173 syncmsg msg;
174 int len = strlen(path);
175
176 msg.req.id = ID_STAT;
177 msg.req.namelen = htoll(len);
178
Dan Albert66a91b02015-02-24 21:26:58 -0800179 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
180 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800181 return -1;
182 }
183
184 return 0;
185}
186
187static int sync_finish_readtime(int fd, unsigned int *timestamp,
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200188 unsigned int *mode, unsigned int *size)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800189{
190 syncmsg msg;
191
Dan Albert66a91b02015-02-24 21:26:58 -0800192 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800193 return -1;
194
195 if(msg.stat.id != ID_STAT)
196 return -1;
197
198 *timestamp = ltohl(msg.stat.time);
199 *mode = ltohl(msg.stat.mode);
200 *size = ltohl(msg.stat.size);
201
202 return 0;
203}
204
205int sync_readmode(int fd, const char *path, unsigned *mode)
206{
207 syncmsg msg;
208 int len = strlen(path);
209
210 msg.req.id = ID_STAT;
211 msg.req.namelen = htoll(len);
212
Dan Albert66a91b02015-02-24 21:26:58 -0800213 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
214 !WriteFdExactly(fd, path, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800215 return -1;
216 }
217
Dan Albert66a91b02015-02-24 21:26:58 -0800218 if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800219 return -1;
220 }
221
222 if(msg.stat.id != ID_STAT) {
223 return -1;
224 }
225
226 *mode = ltohl(msg.stat.mode);
227 return 0;
228}
229
Mark Lindner9f9d1452014-03-11 17:55:59 -0700230static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800231{
232 int lfd, err = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700233 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800234
235 lfd = adb_open(path, O_RDONLY);
236 if(lfd < 0) {
237 fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
238 return -1;
239 }
240
Mark Lindner9f9d1452014-03-11 17:55:59 -0700241 if (show_progress) {
242 // Determine local file size.
243 struct stat st;
eric.yan466d3f42015-02-03 22:16:29 +0800244 if (stat(path, &st)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700245 fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
246 return -1;
247 }
248
249 size = st.st_size;
250 }
251
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800252 sbuf->id = ID_DATA;
253 for(;;) {
254 int ret;
255
256 ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
257 if(!ret)
258 break;
259
260 if(ret < 0) {
261 if(errno == EINTR)
262 continue;
263 fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
264 break;
265 }
266
267 sbuf->size = htoll(ret);
Dan Albert66a91b02015-02-24 21:26:58 -0800268 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800269 err = -1;
270 break;
271 }
272 total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700273
274 if (show_progress) {
275 print_transfer_progress(total_bytes, size);
276 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800277 }
278
279 adb_close(lfd);
280 return err;
281}
282
Mark Lindner9f9d1452014-03-11 17:55:59 -0700283static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
284 int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800285{
286 int err = 0;
287 int total = 0;
288
289 sbuf->id = ID_DATA;
290 while (total < size) {
291 int count = size - total;
292 if (count > SYNC_DATA_MAX) {
293 count = SYNC_DATA_MAX;
294 }
295
296 memcpy(sbuf->data, &file_buffer[total], count);
297 sbuf->size = htoll(count);
Dan Albert66a91b02015-02-24 21:26:58 -0800298 if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800299 err = -1;
300 break;
301 }
302 total += count;
303 total_bytes += count;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700304
305 if (show_progress) {
306 print_transfer_progress(total, size);
307 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800308 }
309
310 return err;
311}
312
Elliott Hughes944e1d72015-01-12 14:26:36 -0800313#if defined(_WIN32)
314extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
315#else
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800316static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
317{
318 int len, ret;
319
320 len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
321 if(len < 0) {
322 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
323 return -1;
324 }
325 sbuf->data[len] = '\0';
326
327 sbuf->size = htoll(len + 1);
328 sbuf->id = ID_DATA;
329
Dan Albert66a91b02015-02-24 21:26:58 -0800330 ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800331 if(ret)
332 return -1;
333
334 total_bytes += len + 1;
335
336 return 0;
337}
338#endif
339
340static int sync_send(int fd, const char *lpath, const char *rpath,
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700341 unsigned mtime, mode_t mode, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800342{
343 syncmsg msg;
344 int len, r;
345 syncsendbuf *sbuf = &send_buffer;
346 char* file_buffer = NULL;
347 int size = 0;
348 char tmp[64];
349
350 len = strlen(rpath);
351 if(len > 1024) goto fail;
352
353 snprintf(tmp, sizeof(tmp), ",%d", mode);
354 r = strlen(tmp);
355
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800356 msg.req.id = ID_SEND;
357 msg.req.namelen = htoll(len + r);
358
Dan Albert66a91b02015-02-24 21:26:58 -0800359 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
360 !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800361 free(file_buffer);
362 goto fail;
363 }
364
365 if (file_buffer) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700366 write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800367 free(file_buffer);
368 } else if (S_ISREG(mode))
Mark Lindner9f9d1452014-03-11 17:55:59 -0700369 write_data_file(fd, lpath, sbuf, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800370 else if (S_ISLNK(mode))
371 write_data_link(fd, lpath, sbuf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800372 else
373 goto fail;
374
375 msg.data.id = ID_DONE;
376 msg.data.size = htoll(mtime);
Dan Albert66a91b02015-02-24 21:26:58 -0800377 if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800378 goto fail;
379
Dan Albert66a91b02015-02-24 21:26:58 -0800380 if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800381 return -1;
382
383 if(msg.status.id != ID_OKAY) {
384 if(msg.status.id == ID_FAIL) {
385 len = ltohl(msg.status.msglen);
386 if(len > 256) len = 256;
Dan Albert66a91b02015-02-24 21:26:58 -0800387 if(!ReadFdExactly(fd, sbuf->data, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800388 return -1;
389 }
390 sbuf->data[len] = 0;
391 } else
392 strcpy(sbuf->data, "unknown reason");
393
394 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
395 return -1;
396 }
397
398 return 0;
399
400fail:
401 fprintf(stderr,"protocol failure\n");
402 adb_close(fd);
403 return -1;
404}
405
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700406static int mkdirs(const char *name)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800407{
408 int ret;
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700409 char *x = (char *)name + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800410
411 for(;;) {
412 x = adb_dirstart(x);
413 if(x == 0) return 0;
414 *x = 0;
415 ret = adb_mkdir(name, 0775);
416 *x = OS_PATH_SEPARATOR;
417 if((ret < 0) && (errno != EEXIST)) {
418 return ret;
419 }
420 x++;
421 }
422 return 0;
423}
424
Mark Lindner9f9d1452014-03-11 17:55:59 -0700425int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800426{
427 syncmsg msg;
428 int len;
429 int lfd = -1;
430 char *buffer = send_buffer.data;
431 unsigned id;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700432 unsigned long long size = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800433
434 len = strlen(rpath);
435 if(len > 1024) return -1;
436
Mark Lindner9f9d1452014-03-11 17:55:59 -0700437 if (show_progress) {
438 // Determine remote file size.
439 syncmsg stat_msg;
440 stat_msg.req.id = ID_STAT;
441 stat_msg.req.namelen = htoll(len);
442
Dan Albert66a91b02015-02-24 21:26:58 -0800443 if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
444 !WriteFdExactly(fd, rpath, len)) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700445 return -1;
446 }
447
Dan Albert66a91b02015-02-24 21:26:58 -0800448 if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700449 return -1;
450 }
451
452 if (stat_msg.stat.id != ID_STAT) return -1;
453
454 size = ltohl(stat_msg.stat.size);
455 }
456
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800457 msg.req.id = ID_RECV;
458 msg.req.namelen = htoll(len);
Dan Albert66a91b02015-02-24 21:26:58 -0800459 if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
460 !WriteFdExactly(fd, rpath, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800461 return -1;
462 }
463
Dan Albert66a91b02015-02-24 21:26:58 -0800464 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800465 return -1;
466 }
467 id = msg.data.id;
468
469 if((id == ID_DATA) || (id == ID_DONE)) {
470 adb_unlink(lpath);
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700471 mkdirs(lpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800472 lfd = adb_creat(lpath, 0644);
473 if(lfd < 0) {
474 fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
475 return -1;
476 }
477 goto handle_data;
478 } else {
479 goto remote_error;
480 }
481
482 for(;;) {
Dan Albert66a91b02015-02-24 21:26:58 -0800483 if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800484 return -1;
485 }
486 id = msg.data.id;
487
488 handle_data:
489 len = ltohl(msg.data.size);
490 if(id == ID_DONE) break;
491 if(id != ID_DATA) goto remote_error;
492 if(len > SYNC_DATA_MAX) {
493 fprintf(stderr,"data overrun\n");
494 adb_close(lfd);
495 return -1;
496 }
497
Dan Albert66a91b02015-02-24 21:26:58 -0800498 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800499 adb_close(lfd);
500 return -1;
501 }
502
Dan Albert66a91b02015-02-24 21:26:58 -0800503 if(!WriteFdExactly(lfd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800504 fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
505 adb_close(lfd);
506 return -1;
507 }
508
509 total_bytes += len;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700510
511 if (show_progress) {
512 print_transfer_progress(total_bytes, size);
513 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800514 }
515
516 adb_close(lfd);
517 return 0;
518
519remote_error:
520 adb_close(lfd);
521 adb_unlink(lpath);
522
523 if(id == ID_FAIL) {
524 len = ltohl(msg.data.size);
525 if(len > 256) len = 256;
Dan Albert66a91b02015-02-24 21:26:58 -0800526 if(!ReadFdExactly(fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800527 return -1;
528 }
529 buffer[len] = 0;
530 } else {
531 memcpy(buffer, &id, 4);
532 buffer[4] = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800533 }
534 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
535 return 0;
536}
537
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800538/* --- */
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800539static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
540 const char *name, void *cookie)
541{
542 printf("%08x %08x %08x %s\n", mode, size, time, name);
543}
544
545int do_sync_ls(const char *path)
546{
547 int fd = adb_connect("sync:");
548 if(fd < 0) {
549 fprintf(stderr,"error: %s\n", adb_error());
550 return 1;
551 }
552
553 if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
554 return 1;
555 } else {
556 sync_quit(fd);
557 return 0;
558 }
559}
560
561typedef struct copyinfo copyinfo;
562
563struct copyinfo
564{
565 copyinfo *next;
566 const char *src;
567 const char *dst;
568 unsigned int time;
569 unsigned int mode;
570 unsigned int size;
571 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800572};
573
574copyinfo *mkcopyinfo(const char *spath, const char *dpath,
575 const char *name, int isdir)
576{
577 int slen = strlen(spath);
578 int dlen = strlen(dpath);
579 int nlen = strlen(name);
580 int ssize = slen + nlen + 2;
581 int dsize = dlen + nlen + 2;
582
Dan Albertf30d73c2015-02-25 17:51:28 -0800583 copyinfo *ci = reinterpret_cast<copyinfo*>(
584 malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800585 if(ci == 0) {
586 fprintf(stderr,"out of memory\n");
587 abort();
588 }
589
590 ci->next = 0;
591 ci->time = 0;
592 ci->mode = 0;
593 ci->size = 0;
594 ci->flag = 0;
595 ci->src = (const char*)(ci + 1);
596 ci->dst = ci->src + ssize;
597 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
598 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
599
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800600 return ci;
601}
602
603
604static int local_build_list(copyinfo **filelist,
605 const char *lpath, const char *rpath)
606{
607 DIR *d;
608 struct dirent *de;
609 struct stat st;
610 copyinfo *dirlist = 0;
611 copyinfo *ci, *next;
612
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800613 d = opendir(lpath);
614 if(d == 0) {
615 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
616 return -1;
617 }
618
619 while((de = readdir(d))) {
620 char stat_path[PATH_MAX];
621 char *name = de->d_name;
622
623 if(name[0] == '.') {
624 if(name[1] == 0) continue;
625 if((name[1] == '.') && (name[2] == 0)) continue;
626 }
627
628 /*
629 * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
630 * always returns DT_UNKNOWN, so we just use stat() for all cases.
631 */
632 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
633 continue;
634 strcpy(stat_path, lpath);
635 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800636
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700637 if(!lstat(stat_path, &st)) {
638 if (S_ISDIR(st.st_mode)) {
639 ci = mkcopyinfo(lpath, rpath, name, 1);
640 ci->next = dirlist;
641 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800642 } else {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700643 ci = mkcopyinfo(lpath, rpath, name, 0);
644 if(lstat(ci->src, &st)) {
645 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
646 free(ci);
647 closedir(d);
648 return -1;
649 }
650 if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
651 fprintf(stderr, "skipping special file '%s'\n", ci->src);
652 free(ci);
653 } else {
654 ci->time = st.st_mtime;
655 ci->mode = st.st_mode;
656 ci->size = st.st_size;
657 ci->next = *filelist;
658 *filelist = ci;
659 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800660 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700661 } else {
662 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800663 }
664 }
665
666 closedir(d);
667
668 for(ci = dirlist; ci != 0; ci = next) {
669 next = ci->next;
670 local_build_list(filelist, ci->src, ci->dst);
671 free(ci);
672 }
673
674 return 0;
675}
676
677
Anthony Newnamdd2db142010-02-22 08:36:49 -0600678static 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 -0800679{
680 copyinfo *filelist = 0;
681 copyinfo *ci, *next;
682 int pushed = 0;
683 int skipped = 0;
684
685 if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
686 if(lpath[strlen(lpath) - 1] != '/') {
687 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800688 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800689 if(tmp == 0) return -1;
690 snprintf(tmp, tmplen, "%s/",lpath);
691 lpath = tmp;
692 }
693 if(rpath[strlen(rpath) - 1] != '/') {
694 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800695 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800696 if(tmp == 0) return -1;
697 snprintf(tmp, tmplen, "%s/",rpath);
698 rpath = tmp;
699 }
700
701 if(local_build_list(&filelist, lpath, rpath)) {
702 return -1;
703 }
704
705 if(checktimestamps){
706 for(ci = filelist; ci != 0; ci = ci->next) {
707 if(sync_start_readtime(fd, ci->dst)) {
708 return 1;
709 }
710 }
711 for(ci = filelist; ci != 0; ci = ci->next) {
712 unsigned int timestamp, mode, size;
713 if(sync_finish_readtime(fd, &timestamp, &mode, &size))
714 return 1;
715 if(size == ci->size) {
716 /* for links, we cannot update the atime/mtime */
717 if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
718 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
719 ci->flag = 1;
720 }
721 }
722 }
723 for(ci = filelist; ci != 0; ci = next) {
724 next = ci->next;
725 if(ci->flag == 0) {
Anthony Newnamdd2db142010-02-22 08:36:49 -0600726 fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
727 if(!listonly &&
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700728 sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
Mark Lindner9f9d1452014-03-11 17:55:59 -0700729 0 /* no show progress */)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800730 return 1;
731 }
732 pushed++;
733 } else {
734 skipped++;
735 }
736 free(ci);
737 }
738
739 fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
740 pushed, (pushed == 1) ? "" : "s",
741 skipped, (skipped == 1) ? "" : "s");
742
743 return 0;
744}
745
746
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700747int do_sync_push(const char *lpath, const char *rpath, int show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800748{
749 struct stat st;
750 unsigned mode;
751 int fd;
752
753 fd = adb_connect("sync:");
754 if(fd < 0) {
755 fprintf(stderr,"error: %s\n", adb_error());
756 return 1;
757 }
758
759 if(stat(lpath, &st)) {
760 fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
761 sync_quit(fd);
762 return 1;
763 }
764
765 if(S_ISDIR(st.st_mode)) {
766 BEGIN();
Anthony Newnamdd2db142010-02-22 08:36:49 -0600767 if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800768 return 1;
769 } else {
770 END();
771 sync_quit(fd);
772 }
773 } else {
774 if(sync_readmode(fd, rpath, &mode)) {
775 return 1;
776 }
777 if((mode != 0) && S_ISDIR(mode)) {
778 /* if we're copying a local file to a remote directory,
779 ** we *really* want to copy to remotedir + "/" + localfilename
780 */
781 const char *name = adb_dirstop(lpath);
782 if(name == 0) {
783 name = lpath;
784 } else {
785 name++;
786 }
787 int tmplen = strlen(name) + strlen(rpath) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800788 char *tmp = reinterpret_cast<char*>(
789 malloc(strlen(name) + strlen(rpath) + 2));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800790 if(tmp == 0) return 1;
791 snprintf(tmp, tmplen, "%s/%s", rpath, name);
792 rpath = tmp;
793 }
794 BEGIN();
Jeff Sharkey0e0d2512014-06-09 17:30:57 -0700795 if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800796 return 1;
797 } else {
798 END();
799 sync_quit(fd);
800 return 0;
801 }
802 }
803
804 return 0;
805}
806
807
808typedef struct {
809 copyinfo **filelist;
810 copyinfo **dirlist;
811 const char *rpath;
812 const char *lpath;
813} sync_ls_build_list_cb_args;
814
815void
816sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
817 const char *name, void *cookie)
818{
819 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
820 copyinfo *ci;
821
822 if (S_ISDIR(mode)) {
823 copyinfo **dirlist = args->dirlist;
824
825 /* Don't try recursing down "." or ".." */
826 if (name[0] == '.') {
827 if (name[1] == '\0') return;
828 if ((name[1] == '.') && (name[2] == '\0')) return;
829 }
830
831 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
832 ci->next = *dirlist;
833 *dirlist = ci;
834 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
835 copyinfo **filelist = args->filelist;
836
837 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
838 ci->time = time;
839 ci->mode = mode;
840 ci->size = size;
841 ci->next = *filelist;
842 *filelist = ci;
843 } else {
844 fprintf(stderr, "skipping special file '%s'\n", name);
845 }
846}
847
848static int remote_build_list(int syncfd, copyinfo **filelist,
849 const char *rpath, const char *lpath)
850{
851 copyinfo *dirlist = NULL;
852 sync_ls_build_list_cb_args args;
853
854 args.filelist = filelist;
855 args.dirlist = &dirlist;
856 args.rpath = rpath;
857 args.lpath = lpath;
858
859 /* Put the files/dirs in rpath on the lists. */
860 if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
861 return 1;
862 }
863
864 /* Recurse into each directory we found. */
865 while (dirlist != NULL) {
866 copyinfo *next = dirlist->next;
867 if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
868 return 1;
869 }
870 free(dirlist);
871 dirlist = next;
872 }
873
874 return 0;
875}
876
Dan Albertf30d73c2015-02-25 17:51:28 -0800877static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700878{
Greg Hackmann8b689142014-05-06 08:48:18 -0700879 struct utimbuf times = { time, time };
880 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700881
882 /* use umask for permissions */
883 mode_t mask=umask(0000);
884 umask(mask);
885 int r2 = chmod(lpath, mode & ~mask);
886
887 return r1 ? : r2;
888}
889
Riley Andrewsc736a942014-12-12 13:12:36 -0800890/* Return a copy of the path string with / appended if needed */
891static char *add_slash_to_path(const char *path)
892{
893 if (path[strlen(path) - 1] != '/') {
894 size_t len = strlen(path) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800895 char *path_with_slash = reinterpret_cast<char*>(malloc(len));
Riley Andrewsc736a942014-12-12 13:12:36 -0800896 if (path_with_slash == NULL)
897 return NULL;
898 snprintf(path_with_slash, len, "%s/", path);
899 return path_with_slash;
900 } else {
901 return strdup(path);
902 }
903}
904
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800905static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700906 int copy_attrs)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800907{
908 copyinfo *filelist = 0;
909 copyinfo *ci, *next;
910 int pulled = 0;
911 int skipped = 0;
Riley Andrewsc736a942014-12-12 13:12:36 -0800912 char *rpath_clean = NULL;
913 char *lpath_clean = NULL;
914 int ret = 0;
915
916 if (rpath[0] == '\0' || lpath[0] == '\0') {
917 ret = -1;
918 goto finish;
919 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800920
921 /* Make sure that both directory paths end in a slash. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800922 rpath_clean = add_slash_to_path(rpath);
923 if (!rpath_clean) {
924 ret = -1;
925 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800926 }
Riley Andrewsc736a942014-12-12 13:12:36 -0800927 lpath_clean = add_slash_to_path(lpath);
928 if (!lpath_clean) {
929 ret = -1;
930 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800931 }
932
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800933 /* Recursively build the list of files to copy. */
Riley Andrewsc736a942014-12-12 13:12:36 -0800934 fprintf(stderr, "pull: building file list...\n");
935 if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
936 ret = -1;
937 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800938 }
939
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800940 for (ci = filelist; ci != 0; ci = next) {
941 next = ci->next;
942 if (ci->flag == 0) {
943 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700944 if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800945 ret = -1;
946 goto finish;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800947 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700948
949 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Riley Andrewsc736a942014-12-12 13:12:36 -0800950 ret = -1;
951 goto finish;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700952 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800953 pulled++;
954 } else {
955 skipped++;
956 }
957 free(ci);
958 }
959
960 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
961 pulled, (pulled == 1) ? "" : "s",
962 skipped, (skipped == 1) ? "" : "s");
963
Riley Andrewsc736a942014-12-12 13:12:36 -0800964finish:
965 free(lpath_clean);
966 free(rpath_clean);
967 return ret;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800968}
969
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700970int 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 -0800971{
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700972 unsigned mode, time;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800973 struct stat st;
974
975 int fd;
976
977 fd = adb_connect("sync:");
978 if(fd < 0) {
979 fprintf(stderr,"error: %s\n", adb_error());
980 return 1;
981 }
982
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700983 if(sync_readtime(fd, rpath, &time, &mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800984 return 1;
985 }
986 if(mode == 0) {
987 fprintf(stderr,"remote object '%s' does not exist\n", rpath);
988 return 1;
989 }
990
Matt Fischer3ba90752010-01-04 16:18:50 -0600991 if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800992 if(stat(lpath, &st) == 0) {
993 if(S_ISDIR(st.st_mode)) {
994 /* if we're copying a remote file to a local directory,
995 ** we *really* want to copy to localdir + "/" + remotefilename
996 */
997 const char *name = adb_dirstop(rpath);
998 if(name == 0) {
999 name = rpath;
1000 } else {
1001 name++;
1002 }
1003 int tmplen = strlen(name) + strlen(lpath) + 2;
Dan Albertf30d73c2015-02-25 17:51:28 -08001004 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001005 if(tmp == 0) return 1;
1006 snprintf(tmp, tmplen, "%s/%s", lpath, name);
1007 lpath = tmp;
1008 }
1009 }
1010 BEGIN();
Mark Lindner9f9d1452014-03-11 17:55:59 -07001011 if (sync_recv(fd, rpath, lpath, show_progress)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001012 return 1;
1013 } else {
Lajos Molnar4e23e3c2013-04-19 12:41:09 -07001014 if (copy_attrs && set_time_and_mode(lpath, time, mode))
1015 return 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001016 END();
1017 sync_quit(fd);
1018 return 0;
1019 }
1020 } else if(S_ISDIR(mode)) {
1021 BEGIN();
Lajos Molnar4e23e3c2013-04-19 12:41:09 -07001022 if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001023 return 1;
1024 } else {
1025 END();
1026 sync_quit(fd);
1027 return 0;
1028 }
1029 } else {
1030 fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
1031 return 1;
1032 }
1033}
1034
Anthony Newnamdd2db142010-02-22 08:36:49 -06001035int do_sync_sync(const char *lpath, const char *rpath, int listonly)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001036{
1037 fprintf(stderr,"syncing %s...\n",rpath);
1038
1039 int fd = adb_connect("sync:");
1040 if(fd < 0) {
1041 fprintf(stderr,"error: %s\n", adb_error());
1042 return 1;
1043 }
1044
1045 BEGIN();
Anthony Newnamdd2db142010-02-22 08:36:49 -06001046 if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001047 return 1;
1048 } else {
1049 END();
1050 sync_quit(fd);
1051 return 0;
1052 }
1053}