blob: 94876eec11f88cedc1faad4cbf18d01f2ba87018 [file] [log] [blame]
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Dan Albertb302d122015-02-24 15:51:19 -080017#include <dirent.h>
18#include <errno.h>
Spencer Low803451e2015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albertb302d122015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albertb302d122015-02-24 15:51:19 -080027#include <time.h>
Greg Hackmann8b689142014-05-06 08:48:18 -070028#include <utime.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080029
Elliott Hughes4e7848d2015-08-24 14:49:43 -070030#include <memory>
31
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080032#include "sysdeps.h"
Dan Albertb302d122015-02-24 15:51:19 -080033
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080034#include "adb.h"
35#include "adb_client.h"
Dan Albert66a91b02015-02-24 21:26:58 -080036#include "adb_io.h"
Alex Valléee9163152015-05-06 17:22:25 -040037#include "adb_utils.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080038#include "file_sync_service.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080039
Elliott Hughesb628cb12015-08-03 10:38:08 -070040#include <base/strings.h>
Elliott Hughesd189cfb2015-07-30 17:42:01 -070041#include <base/stringprintf.h>
42
Elliott Hughesb628cb12015-08-03 10:38:08 -070043struct syncsendbuf {
44 unsigned id;
45 unsigned size;
46 char data[SYNC_DATA_MAX];
47};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080048
Elliott Hughesb628cb12015-08-03 10:38:08 -070049static syncsendbuf send_buffer;
50
51static long long NOW() {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080052 struct timeval tv;
53 gettimeofday(&tv, 0);
Elliott Hughesb628cb12015-08-03 10:38:08 -070054 return ((long long) tv.tv_usec) + 1000000LL * ((long long) tv.tv_sec);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080055}
56
Spencer Low803451e2015-05-13 00:02:55 -070057static void print_transfer_progress(uint64_t bytes_current,
58 uint64_t bytes_total) {
Mark Lindner9f9d1452014-03-11 17:55:59 -070059 if (bytes_total == 0) return;
60
Spencer Low803451e2015-05-13 00:02:55 -070061 fprintf(stderr, "\rTransferring: %" PRIu64 "/%" PRIu64 " (%d%%)",
62 bytes_current, bytes_total,
Mark Lindner9f9d1452014-03-11 17:55:59 -070063 (int) (bytes_current * 100 / bytes_total));
64
65 if (bytes_current == bytes_total) {
66 fputc('\n', stderr);
67 }
68
69 fflush(stderr);
70}
71
Elliott Hughesb628cb12015-08-03 10:38:08 -070072static bool SendRequest(int fd, int id, const char* path) {
73 size_t path_length = strlen(path);
74 if (path_length > 1024) {
75 fprintf(stderr, "SendRequest failed: path too long: %zu", path_length);
76 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080077 }
78
Elliott Hughesb628cb12015-08-03 10:38:08 -070079 // Sending header and payload in a single write makes a noticeable
80 // difference to "adb sync" performance.
81 char buf[sizeof(SyncRequest) + path_length] __attribute__((aligned(8)));
82 SyncRequest* req = reinterpret_cast<SyncRequest*>(buf);
83 req->id = id;
Elliott Hughes9e8e3552015-08-24 14:27:03 -070084 req->path_length = path_length;
Elliott Hughesb628cb12015-08-03 10:38:08 -070085 char* data = reinterpret_cast<char*>(req + 1);
86 memcpy(data, path, path_length);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080087
Elliott Hughesb628cb12015-08-03 10:38:08 -070088 return WriteFdExactly(fd, buf, sizeof(buf));
89}
90
91class SyncConnection {
92 public:
93 SyncConnection() : total_bytes(0), start_time_(NOW()) {
94 max = SYNC_DATA_MAX; // TODO: decide at runtime.
95
96 std::string error;
97 fd = adb_connect("sync:", &error);
98 if (fd < 0) {
99 fprintf(stderr, "error: %s\n", error.c_str());
100 }
101 }
102
103 ~SyncConnection() {
104 if (!IsValid()) return;
105
106 SendQuit();
107 ShowTransferRate();
108 adb_close(fd);
109 }
110
111 bool IsValid() { return fd >= 0; }
112
113 uint64_t total_bytes;
114
115 // TODO: add a char[max] buffer here, to replace syncsendbuf...
116 int fd;
117 size_t max;
118
119 private:
120 uint64_t start_time_;
121
122 void SendQuit() {
123 SendRequest(fd, ID_QUIT, ""); // TODO: add a SendResponse?
124 }
125
126 void ShowTransferRate() {
127 uint64_t t = NOW() - start_time_;
128 if (total_bytes == 0 || t == 0) return;
129
130 fprintf(stderr, "%lld KB/s (%" PRId64 " bytes in %lld.%03llds)\n",
131 ((total_bytes * 1000000LL) / t) / 1024LL,
132 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
133 }
134};
135
136typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
137
138static bool sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
139 if (!SendRequest(fd, ID_LIST, path)) return false;
140
141 while (true) {
142 syncmsg msg;
143 if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) return false;
144
145 if (msg.dent.id == ID_DONE) return true;
146 if (msg.dent.id != ID_DENT) return false;
147
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700148 size_t len = msg.dent.namelen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700149 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800150
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700151 char buf[257];
Elliott Hughesb628cb12015-08-03 10:38:08 -0700152 if (!ReadFdExactly(fd, buf, len)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800153 buf[len] = 0;
154
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700155 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf, cookie);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800156 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800157}
158
Elliott Hughesb628cb12015-08-03 10:38:08 -0700159static bool sync_start_stat(SyncConnection& sc, const char* path) {
160 return SendRequest(sc.fd, ID_STAT, path);
161}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800162
Elliott Hughesb628cb12015-08-03 10:38:08 -0700163static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
164 unsigned int* mode, unsigned int* size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800165 syncmsg msg;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700166 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
167 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800168 }
169
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700170 if (timestamp) *timestamp = msg.stat.time;
171 if (mode) *mode = msg.stat.mode;
172 if (size) *size = msg.stat.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800173
Elliott Hughesb628cb12015-08-03 10:38:08 -0700174 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800175}
176
Elliott Hughesb628cb12015-08-03 10:38:08 -0700177static bool sync_stat(SyncConnection& sc, const char* path,
178 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
179 return sync_start_stat(sc, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800180}
181
Spencer Lowc1a31332015-08-28 01:07:30 -0700182static bool write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
Mark Lindner9f9d1452014-03-11 17:55:59 -0700183 unsigned long long size = 0;
Spencer Lowc1a31332015-08-28 01:07:30 -0700184 if (show_progress) {
185 // Determine local file size.
186 struct stat st;
187 if (stat(path, &st) == -1) {
188 fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
189 return false;
190 }
191
192 size = st.st_size;
193 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800194
Elliott Hughesb628cb12015-08-03 10:38:08 -0700195 int lfd = adb_open(path, O_RDONLY);
196 if (lfd < 0) {
197 fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
Spencer Lowc1a31332015-08-28 01:07:30 -0700198 return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700199 }
200
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800201 sbuf->id = ID_DATA;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700202 while (true) {
203 int ret = adb_read(lfd, sbuf->data, sc.max);
Elliott Hughes0bd85872015-08-25 10:59:45 -0700204 if (ret <= 0) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700205 if (ret < 0) {
206 fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
207 adb_close(lfd);
208 return false;
209 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800210 break;
211 }
212
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700213 sbuf->size = ret;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700214 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700215 adb_close(lfd);
216 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800217 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700218 sc.total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700219
220 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700221 print_transfer_progress(sc.total_bytes, size);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700222 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800223 }
224
225 adb_close(lfd);
Spencer Lowc1a31332015-08-28 01:07:30 -0700226 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800227}
228
Elliott Hughes944e1d72015-01-12 14:26:36 -0800229#if defined(_WIN32)
Spencer Lowc1a31332015-08-28 01:07:30 -0700230extern bool write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
Elliott Hughes944e1d72015-01-12 14:26:36 -0800231#else
Spencer Lowc1a31332015-08-28 01:07:30 -0700232static bool write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700233 ssize_t len = readlink(path, sbuf->data, sc.max - 1);
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700234 if (len < 0) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800235 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
Spencer Lowc1a31332015-08-28 01:07:30 -0700236 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800237 }
238 sbuf->data[len] = '\0';
239
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700240 sbuf->size = len + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800241 sbuf->id = ID_DATA;
242
Elliott Hughesb628cb12015-08-03 10:38:08 -0700243 if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700244 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700245 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800246
Elliott Hughesb628cb12015-08-03 10:38:08 -0700247 sc.total_bytes += len + 1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800248
Spencer Lowc1a31332015-08-28 01:07:30 -0700249 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800250}
251#endif
252
Elliott Hughesb628cb12015-08-03 10:38:08 -0700253static bool sync_send(SyncConnection& sc, const char *lpath, const char *rpath,
254 unsigned mtime, mode_t mode, bool show_progress)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800255{
Elliott Hughesb628cb12015-08-03 10:38:08 -0700256 syncsendbuf* sbuf = &send_buffer;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800257
Elliott Hughesb628cb12015-08-03 10:38:08 -0700258 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
259 if (!SendRequest(sc.fd, ID_SEND, path_and_mode.c_str())) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800260
Elliott Hughesb628cb12015-08-03 10:38:08 -0700261 if (S_ISREG(mode)) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700262 if (!write_data_file(sc, lpath, sbuf, show_progress)) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700263 } else if (S_ISLNK(mode)) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700264 if (!write_data_link(sc, lpath, sbuf)) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700265 } else {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800266 goto fail;
267 }
268
Elliott Hughesb628cb12015-08-03 10:38:08 -0700269 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800270 msg.data.id = ID_DONE;
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700271 msg.data.size = mtime;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700272 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800273
Elliott Hughesb628cb12015-08-03 10:38:08 -0700274 if (!ReadFdExactly(sc.fd, &msg.status, sizeof(msg.status))) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800275
Elliott Hughesb628cb12015-08-03 10:38:08 -0700276 if (msg.status.id != ID_OKAY) {
277 if (msg.status.id == ID_FAIL) {
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700278 size_t len = msg.status.msglen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700279 if (len > 256) len = 256;
280 if (!ReadFdExactly(sc.fd, sbuf->data, len)) goto fail;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800281 sbuf->data[len] = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700282 } else {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800283 strcpy(sbuf->data, "unknown reason");
Elliott Hughesb628cb12015-08-03 10:38:08 -0700284 }
285 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
286 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800287 }
288
Elliott Hughesb628cb12015-08-03 10:38:08 -0700289 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800290
291fail:
Elliott Hughesb628cb12015-08-03 10:38:08 -0700292 fprintf(stderr, "protocol failure\n");
293 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800294}
295
Elliott Hughesb628cb12015-08-03 10:38:08 -0700296static int sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bool show_progress) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800297 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800298 int lfd = -1;
299 char *buffer = send_buffer.data;
300 unsigned id;
301
Elliott Hughesb628cb12015-08-03 10:38:08 -0700302 size_t len = strlen(rpath);
303 if (len > 1024) return -1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800304
Elliott Hughesb628cb12015-08-03 10:38:08 -0700305 unsigned size = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700306 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700307 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return -1;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700308 }
309
Elliott Hughesb628cb12015-08-03 10:38:08 -0700310 if (!SendRequest(sc.fd, ID_RECV, rpath)) return -1;
311 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) return -1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800312
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800313 id = msg.data.id;
314
Elliott Hughesb628cb12015-08-03 10:38:08 -0700315 if (id == ID_DATA || id == ID_DONE) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800316 adb_unlink(lpath);
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700317 mkdirs(lpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800318 lfd = adb_creat(lpath, 0644);
319 if(lfd < 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700320 fprintf(stderr, "cannot create '%s': %s\n", lpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800321 return -1;
322 }
323 goto handle_data;
324 } else {
325 goto remote_error;
326 }
327
Elliott Hughesb628cb12015-08-03 10:38:08 -0700328 while (true) {
329 if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700330 adb_close(lfd);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800331 return -1;
332 }
333 id = msg.data.id;
334
335 handle_data:
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700336 len = msg.data.size;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700337 if (id == ID_DONE) break;
338 if (id != ID_DATA) goto remote_error;
339 if (len > sc.max) {
340 fprintf(stderr, "msg.data.size too large: %zu (max %zu)\n", len, sc.max);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800341 adb_close(lfd);
342 return -1;
343 }
344
Elliott Hughesb628cb12015-08-03 10:38:08 -0700345 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800346 adb_close(lfd);
347 return -1;
348 }
349
Dan Albert66a91b02015-02-24 21:26:58 -0800350 if(!WriteFdExactly(lfd, buffer, len)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700351 fprintf(stderr, "cannot write '%s': %s\n", rpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800352 adb_close(lfd);
353 return -1;
354 }
355
Elliott Hughesb628cb12015-08-03 10:38:08 -0700356 sc.total_bytes += len;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700357
358 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700359 print_transfer_progress(sc.total_bytes, size);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700360 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800361 }
362
363 adb_close(lfd);
364 return 0;
365
366remote_error:
367 adb_close(lfd);
368 adb_unlink(lpath);
369
370 if(id == ID_FAIL) {
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700371 len = msg.data.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800372 if(len > 256) len = 256;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700373 if(!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800374 return -1;
375 }
376 buffer[len] = 0;
377 } else {
378 memcpy(buffer, &id, 4);
379 buffer[4] = 0;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800380 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700381 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800382 return 0;
383}
384
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800385static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
Elliott Hughesb628cb12015-08-03 10:38:08 -0700386 const char* name, void* /*cookie*/) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800387 printf("%08x %08x %08x %s\n", mode, size, time, name);
388}
389
Elliott Hughesb628cb12015-08-03 10:38:08 -0700390bool do_sync_ls(const char* path) {
391 SyncConnection sc;
392 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800393
Elliott Hughesb628cb12015-08-03 10:38:08 -0700394 return sync_ls(sc.fd, path, do_sync_ls_cb, 0);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800395}
396
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800397struct copyinfo
398{
399 copyinfo *next;
400 const char *src;
401 const char *dst;
402 unsigned int time;
403 unsigned int mode;
404 unsigned int size;
405 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800406};
407
Elliott Hughes712416a2015-05-05 18:26:10 -0700408static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800409 int slen = strlen(spath);
410 int dlen = strlen(dpath);
411 int nlen = strlen(name);
412 int ssize = slen + nlen + 2;
413 int dsize = dlen + nlen + 2;
414
Elliott Hughes712416a2015-05-05 18:26:10 -0700415 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800416 if(ci == 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700417 fprintf(stderr, "out of memory\n");
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800418 abort();
419 }
420
421 ci->next = 0;
422 ci->time = 0;
423 ci->mode = 0;
424 ci->size = 0;
425 ci->flag = 0;
426 ci->src = (const char*)(ci + 1);
427 ci->dst = ci->src + ssize;
428 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
429 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
430
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800431 return ci;
432}
433
Elliott Hughesb628cb12015-08-03 10:38:08 -0700434static bool IsDotOrDotDot(const char* name) {
435 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
436}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800437
Elliott Hughesb628cb12015-08-03 10:38:08 -0700438static int local_build_list(copyinfo** filelist, const char* lpath, const char* rpath) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800439 copyinfo *dirlist = 0;
440 copyinfo *ci, *next;
441
Elliott Hughesb628cb12015-08-03 10:38:08 -0700442 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
443 if (!dir) {
444 fprintf(stderr, "cannot open '%s': %s\n", lpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800445 return -1;
446 }
447
Elliott Hughesb628cb12015-08-03 10:38:08 -0700448 dirent *de;
449 while ((de = readdir(dir.get()))) {
450 if (IsDotOrDotDot(de->d_name)) continue;
451
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800452 char stat_path[PATH_MAX];
Elliott Hughesb628cb12015-08-03 10:38:08 -0700453 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
454 fprintf(stderr, "skipping long path '%s%s'\n", lpath, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800455 continue;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700456 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800457 strcpy(stat_path, lpath);
458 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800459
Elliott Hughesb628cb12015-08-03 10:38:08 -0700460 struct stat st;
461 if (!lstat(stat_path, &st)) {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700462 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700463 ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700464 ci->next = dirlist;
465 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800466 } else {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700467 ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
468 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700469 fprintf(stderr, "skipping special file '%s'\n", ci->src);
470 free(ci);
471 } else {
472 ci->time = st.st_mtime;
473 ci->mode = st.st_mode;
474 ci->size = st.st_size;
475 ci->next = *filelist;
476 *filelist = ci;
477 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800478 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700479 } else {
480 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800481 }
482 }
483
Elliott Hughesb628cb12015-08-03 10:38:08 -0700484 // Close this directory and recurse.
485 dir.reset();
486 for (ci = dirlist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800487 next = ci->next;
488 local_build_list(filelist, ci->src, ci->dst);
489 free(ci);
490 }
491
492 return 0;
493}
494
Elliott Hughesb628cb12015-08-03 10:38:08 -0700495static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
496 bool check_timestamps, bool list_only) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800497 copyinfo *filelist = 0;
498 copyinfo *ci, *next;
499 int pushed = 0;
500 int skipped = 0;
501
Elliott Hughesb628cb12015-08-03 10:38:08 -0700502 if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
503 if (lpath[strlen(lpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800504 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800505 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700506 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800507 snprintf(tmp, tmplen, "%s/",lpath);
508 lpath = tmp;
509 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700510 if (rpath[strlen(rpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800511 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800512 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700513 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800514 snprintf(tmp, tmplen, "%s/",rpath);
515 rpath = tmp;
516 }
517
Elliott Hughesb628cb12015-08-03 10:38:08 -0700518 if (local_build_list(&filelist, lpath, rpath)) {
519 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800520 }
521
Elliott Hughesb628cb12015-08-03 10:38:08 -0700522 if (check_timestamps) {
523 for (ci = filelist; ci != 0; ci = ci->next) {
524 if (!sync_start_stat(sc, ci->dst)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800525 }
526 for(ci = filelist; ci != 0; ci = ci->next) {
527 unsigned int timestamp, mode, size;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700528 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
529 if (size == ci->size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800530 /* for links, we cannot update the atime/mtime */
Elliott Hughesb628cb12015-08-03 10:38:08 -0700531 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
532 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800533 ci->flag = 1;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700534 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800535 }
536 }
537 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700538 for (ci = filelist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800539 next = ci->next;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700540 if (ci->flag == 0) {
541 fprintf(stderr, "%spush: %s -> %s\n", list_only ? "would " : "", ci->src, ci->dst);
542 if (!list_only && !sync_send(sc, ci->src, ci->dst, ci->time, ci->mode, false)) {
543 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800544 }
545 pushed++;
546 } else {
547 skipped++;
548 }
549 free(ci);
550 }
551
Elliott Hughesb628cb12015-08-03 10:38:08 -0700552 fprintf(stderr, "%d file%s pushed. %d file%s skipped.\n",
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800553 pushed, (pushed == 1) ? "" : "s",
554 skipped, (skipped == 1) ? "" : "s");
555
Elliott Hughesb628cb12015-08-03 10:38:08 -0700556 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800557}
558
Elliott Hughesb628cb12015-08-03 10:38:08 -0700559bool do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
560 SyncConnection sc;
561 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800562
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700563 struct stat st;
564 if (stat(lpath, &st)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700565 fprintf(stderr, "cannot stat '%s': %s\n", lpath, strerror(errno));
566 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800567 }
568
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700569 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700570 return copy_local_dir_remote(sc, lpath, rpath, false, false);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800571 }
572
Elliott Hughesb628cb12015-08-03 10:38:08 -0700573 unsigned mode;
574 if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
575 std::string path_holder;
576 if (mode != 0 && S_ISDIR(mode)) {
577 // If we're copying a local file to a remote directory,
578 // we really want to copy to remote_dir + "/" + local_filename.
579 path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
580 rpath = path_holder.c_str();
581 }
582 return sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800583}
584
585
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700586struct sync_ls_build_list_cb_args {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800587 copyinfo **filelist;
588 copyinfo **dirlist;
589 const char *rpath;
590 const char *lpath;
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700591};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800592
Elliott Hughes712416a2015-05-05 18:26:10 -0700593static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
594 const char* name, void* cookie)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800595{
596 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
597 copyinfo *ci;
598
599 if (S_ISDIR(mode)) {
600 copyinfo **dirlist = args->dirlist;
601
Elliott Hughesb628cb12015-08-03 10:38:08 -0700602 // Don't try recursing down "." or "..".
603 if (IsDotOrDotDot(name)) return;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800604
605 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
606 ci->next = *dirlist;
607 *dirlist = ci;
608 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
609 copyinfo **filelist = args->filelist;
610
611 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
612 ci->time = time;
613 ci->mode = mode;
614 ci->size = size;
615 ci->next = *filelist;
616 *filelist = ci;
617 } else {
618 fprintf(stderr, "skipping special file '%s'\n", name);
619 }
620}
621
Elliott Hughesb628cb12015-08-03 10:38:08 -0700622static bool remote_build_list(int syncfd, copyinfo **filelist,
623 const char *rpath, const char *lpath) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800624 copyinfo *dirlist = NULL;
625 sync_ls_build_list_cb_args args;
626
627 args.filelist = filelist;
628 args.dirlist = &dirlist;
629 args.rpath = rpath;
630 args.lpath = lpath;
631
Elliott Hughesb628cb12015-08-03 10:38:08 -0700632 // Put the files/dirs in rpath on the lists.
633 if (!sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
634 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800635 }
636
Elliott Hughesb628cb12015-08-03 10:38:08 -0700637 // Recurse into each directory we found.
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800638 while (dirlist != NULL) {
639 copyinfo *next = dirlist->next;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700640 if (!remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
641 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800642 }
643 free(dirlist);
644 dirlist = next;
645 }
646
Elliott Hughesb628cb12015-08-03 10:38:08 -0700647 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800648}
649
Dan Albertf30d73c2015-02-25 17:51:28 -0800650static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700651{
Greg Hackmann8b689142014-05-06 08:48:18 -0700652 struct utimbuf times = { time, time };
653 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700654
655 /* use umask for permissions */
656 mode_t mask=umask(0000);
657 umask(mask);
658 int r2 = chmod(lpath, mode & ~mask);
659
660 return r1 ? : r2;
661}
662
Elliott Hughesb628cb12015-08-03 10:38:08 -0700663static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
664 int copy_attrs) {
665 // Make sure that both directory paths end in a slash.
666 std::string rpath_clean(rpath);
667 std::string lpath_clean(lpath);
668 if (rpath_clean.empty() || lpath_clean.empty()) return false;
669 if (rpath_clean.back() != '/') rpath_clean.push_back('/');
670 if (lpath_clean.back() != '/') lpath_clean.push_back('/');
Riley Andrewsc736a942014-12-12 13:12:36 -0800671
Elliott Hughesb628cb12015-08-03 10:38:08 -0700672 // Recursively build the list of files to copy.
673 fprintf(stderr, "pull: building file list...\n");
674 copyinfo* filelist = nullptr;
675 if (!remote_build_list(sc.fd, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
676
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800677 int pulled = 0;
678 int skipped = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700679 copyinfo* ci = filelist;
680 while (ci) {
681 copyinfo* next = ci->next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800682 if (ci->flag == 0) {
683 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700684 if (sync_recv(sc, ci->src, ci->dst, false)) {
685 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800686 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700687
688 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700689 return false;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700690 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800691 pulled++;
692 } else {
693 skipped++;
694 }
695 free(ci);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700696 ci = next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800697 }
698
699 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
700 pulled, (pulled == 1) ? "" : "s",
701 skipped, (skipped == 1) ? "" : "s");
Elliott Hughesb628cb12015-08-03 10:38:08 -0700702 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800703}
704
Elliott Hughesb628cb12015-08-03 10:38:08 -0700705bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
706 SyncConnection sc;
707 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800708
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700709 unsigned mode, time;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700710 if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700711 if (mode == 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700712 fprintf(stderr, "remote object '%s' does not exist\n", rpath);
713 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800714 }
715
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700716 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
717 std::string path_holder;
718 struct stat st;
719 if (stat(lpath, &st) == 0) {
720 if (S_ISDIR(st.st_mode)) {
721 // If we're copying a remote file to a local directory,
722 // we really want to copy to local_dir + "/" + basename(remote).
723 path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
724 lpath = path_holder.c_str();
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800725 }
726 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700727 if (sync_recv(sc, rpath, lpath, show_progress)) {
728 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800729 } else {
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700730 if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700731 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700732 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800733 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700734 return true;
735 } else if (S_ISDIR(mode)) {
736 return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800737 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700738
739 fprintf(stderr, "remote object '%s' not a file or directory\n", rpath);
740 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800741}
742
Elliott Hughesb628cb12015-08-03 10:38:08 -0700743bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesc5a12b22015-04-21 10:17:07 -0700744 fprintf(stderr, "syncing %s...\n", rpath.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800745
Elliott Hughesb628cb12015-08-03 10:38:08 -0700746 SyncConnection sc;
747 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800748
Elliott Hughesb628cb12015-08-03 10:38:08 -0700749 return copy_local_dir_remote(sc, lpath.c_str(), rpath.c_str(), true, list_only);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800750}