blob: 5513e8f323fcde128655039834654076b2023a79 [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>
Elliott Hughesdde00be2015-09-27 12:55:37 -070028#include <unistd.h>
Greg Hackmann8b689142014-05-06 08:48:18 -070029#include <utime.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080030
Elliott Hughes4e7848d2015-08-24 14:49:43 -070031#include <memory>
32
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080033#include "sysdeps.h"
Dan Albertb302d122015-02-24 15:51:19 -080034
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080035#include "adb.h"
36#include "adb_client.h"
Dan Albert66a91b02015-02-24 21:26:58 -080037#include "adb_io.h"
Alex Valléee9163152015-05-06 17:22:25 -040038#include "adb_utils.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080039#include "file_sync_service.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080040
Elliott Hughesdde00be2015-09-27 12:55:37 -070041#include <base/file.h>
Elliott Hughesb628cb12015-08-03 10:38:08 -070042#include <base/strings.h>
Elliott Hughesd189cfb2015-07-30 17:42:01 -070043#include <base/stringprintf.h>
44
Elliott Hughesb628cb12015-08-03 10:38:08 -070045struct syncsendbuf {
46 unsigned id;
47 unsigned size;
48 char data[SYNC_DATA_MAX];
49};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080050
Elliott Hughesb628cb12015-08-03 10:38:08 -070051static 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 -070072class SyncConnection {
73 public:
74 SyncConnection() : total_bytes(0), start_time_(NOW()) {
75 max = SYNC_DATA_MAX; // TODO: decide at runtime.
76
77 std::string error;
78 fd = adb_connect("sync:", &error);
79 if (fd < 0) {
80 fprintf(stderr, "error: %s\n", error.c_str());
81 }
82 }
83
84 ~SyncConnection() {
85 if (!IsValid()) return;
86
87 SendQuit();
88 ShowTransferRate();
89 adb_close(fd);
90 }
91
92 bool IsValid() { return fd >= 0; }
93
Elliott Hughesdde00be2015-09-27 12:55:37 -070094 bool SendRequest(int id, const char* path_and_mode) {
95 size_t path_length = strlen(path_and_mode);
96 if (path_length > 1024) {
97 fprintf(stderr, "SendRequest failed: path too long: %zu", path_length);
98 errno = ENAMETOOLONG;
99 return false;
100 }
101
102 // Sending header and payload in a single write makes a noticeable
103 // difference to "adb sync" performance.
104 char buf[sizeof(SyncRequest) + path_length];
105 SyncRequest* req = reinterpret_cast<SyncRequest*>(buf);
106 req->id = id;
107 req->path_length = path_length;
108 char* data = reinterpret_cast<char*>(req + 1);
109 memcpy(data, path_and_mode, path_length);
110
111 return WriteFdExactly(fd, buf, sizeof(buf));
112 }
113
114 // Sending header, payload, and footer in a single write makes a huge
115 // difference to "adb sync" performance.
116 bool SendSmallFile(const char* path_and_mode,
117 const char* data, size_t data_length,
118 unsigned mtime) {
119 size_t path_length = strlen(path_and_mode);
120 if (path_length > 1024) {
121 fprintf(stderr, "SendSmallFile failed: path too long: %zu", path_length);
122 errno = ENAMETOOLONG;
123 return false;
124 }
125
126 char buf[sizeof(SyncRequest) + path_length +
127 sizeof(SyncRequest) + data_length +
128 sizeof(SyncRequest)];
129 char* p = buf;
130
131 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
132 req_send->id = ID_SEND;
133 req_send->path_length = path_length;
134 p += sizeof(SyncRequest);
135 memcpy(p, path_and_mode, path_length);
136 p += path_length;
137
138 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
139 req_data->id = ID_DATA;
140 req_data->path_length = data_length;
141 p += sizeof(SyncRequest);
142 memcpy(p, data, data_length);
143 p += data_length;
144
145 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
146 req_done->id = ID_DONE;
147 req_done->path_length = mtime;
148 p += sizeof(SyncRequest);
149
150 if (!WriteFdExactly(fd, buf, (p-buf))) return false;
151
152 total_bytes += data_length;
153 return true;
154 }
155
156 bool CopyDone(const char* from, const char* to) {
157 syncmsg msg;
158 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
159 fprintf(stderr, "failed to copy '%s' to '%s': no ID_DONE: %s\n",
160 from, to, strerror(errno));
161 return false;
162 }
163 if (msg.status.id == ID_OKAY) {
164 return true;
165 }
166 if (msg.status.id != ID_FAIL) {
167 fprintf(stderr, "failed to copy '%s' to '%s': unknown reason\n", from, to);
168 return false;
169 }
170 char buffer[msg.status.msglen + 1];
171 if (!ReadFdExactly(fd, buffer, msg.status.msglen)) {
172 fprintf(stderr, "failed to copy '%s' to '%s'; failed to read reason (!): %s\n",
173 from, to, strerror(errno));
174 return false;
175 }
176 buffer[msg.status.msglen] = 0;
177 fprintf(stderr, "failed to copy '%s' to '%s': %s\n", from, to, buffer);
178 return false;
179 }
180
Elliott Hughesb628cb12015-08-03 10:38:08 -0700181 uint64_t total_bytes;
182
183 // TODO: add a char[max] buffer here, to replace syncsendbuf...
184 int fd;
185 size_t max;
186
187 private:
188 uint64_t start_time_;
189
190 void SendQuit() {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700191 SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesb628cb12015-08-03 10:38:08 -0700192 }
193
194 void ShowTransferRate() {
195 uint64_t t = NOW() - start_time_;
196 if (total_bytes == 0 || t == 0) return;
197
198 fprintf(stderr, "%lld KB/s (%" PRId64 " bytes in %lld.%03llds)\n",
199 ((total_bytes * 1000000LL) / t) / 1024LL,
200 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
201 }
202};
203
204typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
205
Elliott Hughesdde00be2015-09-27 12:55:37 -0700206static bool sync_ls(SyncConnection& sc, const char* path, sync_ls_cb func, void* cookie) {
207 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700208
209 while (true) {
210 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700211 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700212
213 if (msg.dent.id == ID_DONE) return true;
214 if (msg.dent.id != ID_DENT) return false;
215
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700216 size_t len = msg.dent.namelen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700217 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800218
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700219 char buf[257];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700220 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800221 buf[len] = 0;
222
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700223 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf, cookie);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800224 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800225}
226
Elliott Hughesb628cb12015-08-03 10:38:08 -0700227static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
228 unsigned int* mode, unsigned int* size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800229 syncmsg msg;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700230 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
231 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800232 }
233
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700234 if (timestamp) *timestamp = msg.stat.time;
235 if (mode) *mode = msg.stat.mode;
236 if (size) *size = msg.stat.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800237
Elliott Hughesb628cb12015-08-03 10:38:08 -0700238 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800239}
240
Elliott Hughesb628cb12015-08-03 10:38:08 -0700241static bool sync_stat(SyncConnection& sc, const char* path,
242 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700243 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800244}
245
Elliott Hughesdde00be2015-09-27 12:55:37 -0700246static bool SendLargeFile(SyncConnection& sc, const char* path_and_mode, const char* path,
247 unsigned mtime, bool show_progress) {
248 if (!sc.SendRequest(ID_SEND, path_and_mode)) {
249 fprintf(stderr, "failed to send ID_SEND message '%s': %s\n",
250 path_and_mode, strerror(errno));
251 return false;
252 }
253
Mark Lindner9f9d1452014-03-11 17:55:59 -0700254 unsigned long long size = 0;
Spencer Lowc1a31332015-08-28 01:07:30 -0700255 if (show_progress) {
256 // Determine local file size.
257 struct stat st;
258 if (stat(path, &st) == -1) {
259 fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
260 return false;
261 }
262
263 size = st.st_size;
264 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800265
Elliott Hughesb628cb12015-08-03 10:38:08 -0700266 int lfd = adb_open(path, O_RDONLY);
267 if (lfd < 0) {
268 fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
Spencer Lowc1a31332015-08-28 01:07:30 -0700269 return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700270 }
271
Elliott Hughesdde00be2015-09-27 12:55:37 -0700272 syncsendbuf sbuf;
273 sbuf.id = ID_DATA;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700274 while (true) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700275 int ret = adb_read(lfd, sbuf.data, sc.max);
Elliott Hughes0bd85872015-08-25 10:59:45 -0700276 if (ret <= 0) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700277 if (ret < 0) {
278 fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
279 adb_close(lfd);
280 return false;
281 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800282 break;
283 }
284
Elliott Hughesdde00be2015-09-27 12:55:37 -0700285 sbuf.size = ret;
286 if (!WriteFdExactly(sc.fd, &sbuf, sizeof(unsigned) * 2 + ret)) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700287 adb_close(lfd);
288 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800289 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700290 sc.total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700291
292 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700293 print_transfer_progress(sc.total_bytes, size);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700294 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800295 }
296
297 adb_close(lfd);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800298
Elliott Hughesb628cb12015-08-03 10:38:08 -0700299 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800300 msg.data.id = ID_DONE;
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700301 msg.data.size = mtime;
Elliott Hughesc5d51622015-09-03 11:06:00 -0700302 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700303 fprintf(stderr, "failed to send ID_DONE message for '%s': %s\n", path, strerror(errno));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700304 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800305 }
306
Elliott Hughesb628cb12015-08-03 10:38:08 -0700307 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800308}
309
Elliott Hughesdde00be2015-09-27 12:55:37 -0700310static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
311 unsigned mtime, mode_t mode, bool show_progress)
312{
313 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
314
315 if (S_ISLNK(mode)) {
316#if !defined(_WIN32)
317 char buf[PATH_MAX];
318 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
319 if (data_length == -1) {
320 fprintf(stderr, "readlink '%s' failed: %s\n", lpath, strerror(errno));
321 return false;
322 }
323 buf[data_length++] = '\0';
324
325 if (!sc.SendSmallFile(path_and_mode.c_str(), buf, data_length, mtime)) return false;
326 return sc.CopyDone(lpath, rpath);
327#endif
328 }
329
330 if (!S_ISREG(mode)) {
331 fprintf(stderr, "local file '%s' has unsupported mode: 0o%o\n", lpath, mode);
332 return false;
333 }
334
335 struct stat st;
336 if (stat(lpath, &st) == -1) {
337 fprintf(stderr, "stat '%s' failed: %s\n", lpath, strerror(errno));
338 return false;
339 }
340 if (st.st_size < SYNC_DATA_MAX) {
341 std::string data;
342 if (!android::base::ReadFileToString(lpath, &data)) {
343 fprintf(stderr, "failed to read all of '%s': %s\n", lpath, strerror(errno));
344 return false;
345 }
346 if (!sc.SendSmallFile(path_and_mode.c_str(), data.data(), data.size(), mtime)) return false;
347 } else {
348 if (!SendLargeFile(sc, path_and_mode.c_str(), lpath, mtime, show_progress)) return false;
349 }
350 return sc.CopyDone(lpath, rpath);
351}
352
353static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bool show_progress) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800354 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800355 int lfd = -1;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800356
Elliott Hughesb628cb12015-08-03 10:38:08 -0700357 size_t len = strlen(rpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700358 if (len > 1024) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800359
Elliott Hughesb628cb12015-08-03 10:38:08 -0700360 unsigned size = 0;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700361 if (show_progress) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700362 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700363 }
364
Elliott Hughesdde00be2015-09-27 12:55:37 -0700365 if (!sc.SendRequest(ID_RECV, rpath)) return false;
366 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800367
Elliott Hughesdde00be2015-09-27 12:55:37 -0700368 unsigned id = msg.data.id;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800369
Elliott Hughesb628cb12015-08-03 10:38:08 -0700370 if (id == ID_DATA || id == ID_DONE) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800371 adb_unlink(lpath);
Mark Salyzyn63e39f22014-04-30 09:10:31 -0700372 mkdirs(lpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800373 lfd = adb_creat(lpath, 0644);
374 if(lfd < 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700375 fprintf(stderr, "cannot create '%s': %s\n", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700376 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800377 }
378 goto handle_data;
379 } else {
380 goto remote_error;
381 }
382
Elliott Hughesb628cb12015-08-03 10:38:08 -0700383 while (true) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700384 char buffer[SYNC_DATA_MAX];
385
386 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700387 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700388 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800389 }
390 id = msg.data.id;
391
392 handle_data:
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700393 len = msg.data.size;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700394 if (id == ID_DONE) break;
395 if (id != ID_DATA) goto remote_error;
396 if (len > sc.max) {
397 fprintf(stderr, "msg.data.size too large: %zu (max %zu)\n", len, sc.max);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800398 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700399 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800400 }
401
Elliott Hughesdde00be2015-09-27 12:55:37 -0700402 if (!ReadFdExactly(sc.fd, buffer, len)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800403 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700404 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800405 }
406
Elliott Hughesdde00be2015-09-27 12:55:37 -0700407 if (!WriteFdExactly(lfd, buffer, len)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700408 fprintf(stderr, "cannot write '%s': %s\n", rpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800409 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700410 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800411 }
412
Elliott Hughesb628cb12015-08-03 10:38:08 -0700413 sc.total_bytes += len;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700414
415 if (show_progress) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700416 print_transfer_progress(sc.total_bytes, size);
Mark Lindner9f9d1452014-03-11 17:55:59 -0700417 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800418 }
419
420 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700421 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800422
423remote_error:
424 adb_close(lfd);
425 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700426 sc.CopyDone(rpath, lpath);
427 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800428}
429
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800430static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
Elliott Hughesb628cb12015-08-03 10:38:08 -0700431 const char* name, void* /*cookie*/) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800432 printf("%08x %08x %08x %s\n", mode, size, time, name);
433}
434
Elliott Hughesb628cb12015-08-03 10:38:08 -0700435bool do_sync_ls(const char* path) {
436 SyncConnection sc;
437 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800438
Elliott Hughesdde00be2015-09-27 12:55:37 -0700439 return sync_ls(sc, path, do_sync_ls_cb, 0);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800440}
441
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800442struct copyinfo
443{
444 copyinfo *next;
445 const char *src;
446 const char *dst;
447 unsigned int time;
448 unsigned int mode;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700449 uint64_t size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800450 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800451};
452
Elliott Hughes712416a2015-05-05 18:26:10 -0700453static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800454 int slen = strlen(spath);
455 int dlen = strlen(dpath);
456 int nlen = strlen(name);
457 int ssize = slen + nlen + 2;
458 int dsize = dlen + nlen + 2;
459
Elliott Hughes712416a2015-05-05 18:26:10 -0700460 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800461 if(ci == 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700462 fprintf(stderr, "out of memory\n");
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800463 abort();
464 }
465
466 ci->next = 0;
467 ci->time = 0;
468 ci->mode = 0;
469 ci->size = 0;
470 ci->flag = 0;
471 ci->src = (const char*)(ci + 1);
472 ci->dst = ci->src + ssize;
473 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
474 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
475
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800476 return ci;
477}
478
Elliott Hughesb628cb12015-08-03 10:38:08 -0700479static bool IsDotOrDotDot(const char* name) {
480 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
481}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800482
Elliott Hughesb628cb12015-08-03 10:38:08 -0700483static int local_build_list(copyinfo** filelist, const char* lpath, const char* rpath) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800484 copyinfo *dirlist = 0;
485 copyinfo *ci, *next;
486
Elliott Hughesb628cb12015-08-03 10:38:08 -0700487 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
488 if (!dir) {
489 fprintf(stderr, "cannot open '%s': %s\n", lpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800490 return -1;
491 }
492
Elliott Hughesb628cb12015-08-03 10:38:08 -0700493 dirent *de;
494 while ((de = readdir(dir.get()))) {
495 if (IsDotOrDotDot(de->d_name)) continue;
496
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800497 char stat_path[PATH_MAX];
Elliott Hughesb628cb12015-08-03 10:38:08 -0700498 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
499 fprintf(stderr, "skipping long path '%s%s'\n", lpath, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800500 continue;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700501 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800502 strcpy(stat_path, lpath);
503 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800504
Elliott Hughesb628cb12015-08-03 10:38:08 -0700505 struct stat st;
506 if (!lstat(stat_path, &st)) {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700507 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700508 ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700509 ci->next = dirlist;
510 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800511 } else {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700512 ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
513 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700514 fprintf(stderr, "skipping special file '%s'\n", ci->src);
515 free(ci);
516 } else {
517 ci->time = st.st_mtime;
518 ci->mode = st.st_mode;
519 ci->size = st.st_size;
520 ci->next = *filelist;
521 *filelist = ci;
522 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800523 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700524 } else {
525 fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800526 }
527 }
528
Elliott Hughesb628cb12015-08-03 10:38:08 -0700529 // Close this directory and recurse.
530 dir.reset();
531 for (ci = dirlist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800532 next = ci->next;
533 local_build_list(filelist, ci->src, ci->dst);
534 free(ci);
535 }
536
537 return 0;
538}
539
Elliott Hughesb628cb12015-08-03 10:38:08 -0700540static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
541 bool check_timestamps, bool list_only) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800542 copyinfo *filelist = 0;
543 copyinfo *ci, *next;
544 int pushed = 0;
545 int skipped = 0;
546
Elliott Hughesb628cb12015-08-03 10:38:08 -0700547 if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
548 if (lpath[strlen(lpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800549 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800550 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700551 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800552 snprintf(tmp, tmplen, "%s/",lpath);
553 lpath = tmp;
554 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700555 if (rpath[strlen(rpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800556 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800557 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700558 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800559 snprintf(tmp, tmplen, "%s/",rpath);
560 rpath = tmp;
561 }
562
Elliott Hughesb628cb12015-08-03 10:38:08 -0700563 if (local_build_list(&filelist, lpath, rpath)) {
564 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800565 }
566
Elliott Hughesb628cb12015-08-03 10:38:08 -0700567 if (check_timestamps) {
568 for (ci = filelist; ci != 0; ci = ci->next) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700569 if (!sc.SendRequest(ID_STAT, ci->dst)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800570 }
571 for(ci = filelist; ci != 0; ci = ci->next) {
572 unsigned int timestamp, mode, size;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700573 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
574 if (size == ci->size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800575 /* for links, we cannot update the atime/mtime */
Elliott Hughesb628cb12015-08-03 10:38:08 -0700576 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
577 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800578 ci->flag = 1;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700579 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800580 }
581 }
582 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700583 for (ci = filelist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800584 next = ci->next;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700585 if (ci->flag == 0) {
586 fprintf(stderr, "%spush: %s -> %s\n", list_only ? "would " : "", ci->src, ci->dst);
587 if (!list_only && !sync_send(sc, ci->src, ci->dst, ci->time, ci->mode, false)) {
588 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800589 }
590 pushed++;
591 } else {
592 skipped++;
593 }
594 free(ci);
595 }
596
Elliott Hughesb628cb12015-08-03 10:38:08 -0700597 fprintf(stderr, "%d file%s pushed. %d file%s skipped.\n",
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800598 pushed, (pushed == 1) ? "" : "s",
599 skipped, (skipped == 1) ? "" : "s");
600
Elliott Hughesb628cb12015-08-03 10:38:08 -0700601 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800602}
603
Elliott Hughesb628cb12015-08-03 10:38:08 -0700604bool do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
605 SyncConnection sc;
606 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800607
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700608 struct stat st;
609 if (stat(lpath, &st)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700610 fprintf(stderr, "cannot stat '%s': %s\n", lpath, strerror(errno));
611 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800612 }
613
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700614 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700615 return copy_local_dir_remote(sc, lpath, rpath, false, false);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800616 }
617
Elliott Hughesb628cb12015-08-03 10:38:08 -0700618 unsigned mode;
619 if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
620 std::string path_holder;
621 if (mode != 0 && S_ISDIR(mode)) {
622 // If we're copying a local file to a remote directory,
623 // we really want to copy to remote_dir + "/" + local_filename.
624 path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
625 rpath = path_holder.c_str();
626 }
627 return sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode, show_progress);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800628}
629
630
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700631struct sync_ls_build_list_cb_args {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800632 copyinfo **filelist;
633 copyinfo **dirlist;
634 const char *rpath;
635 const char *lpath;
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700636};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800637
Elliott Hughes712416a2015-05-05 18:26:10 -0700638static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
639 const char* name, void* cookie)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800640{
641 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
642 copyinfo *ci;
643
644 if (S_ISDIR(mode)) {
645 copyinfo **dirlist = args->dirlist;
646
Elliott Hughesb628cb12015-08-03 10:38:08 -0700647 // Don't try recursing down "." or "..".
648 if (IsDotOrDotDot(name)) return;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800649
650 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
651 ci->next = *dirlist;
652 *dirlist = ci;
653 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
654 copyinfo **filelist = args->filelist;
655
656 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
657 ci->time = time;
658 ci->mode = mode;
659 ci->size = size;
660 ci->next = *filelist;
661 *filelist = ci;
662 } else {
663 fprintf(stderr, "skipping special file '%s'\n", name);
664 }
665}
666
Elliott Hughesdde00be2015-09-27 12:55:37 -0700667static bool remote_build_list(SyncConnection& sc, copyinfo **filelist,
Elliott Hughesb628cb12015-08-03 10:38:08 -0700668 const char *rpath, const char *lpath) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800669 copyinfo *dirlist = NULL;
670 sync_ls_build_list_cb_args args;
671
672 args.filelist = filelist;
673 args.dirlist = &dirlist;
674 args.rpath = rpath;
675 args.lpath = lpath;
676
Elliott Hughesb628cb12015-08-03 10:38:08 -0700677 // Put the files/dirs in rpath on the lists.
Elliott Hughesdde00be2015-09-27 12:55:37 -0700678 if (!sync_ls(sc, rpath, sync_ls_build_list_cb, (void *)&args)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700679 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800680 }
681
Elliott Hughesb628cb12015-08-03 10:38:08 -0700682 // Recurse into each directory we found.
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800683 while (dirlist != NULL) {
684 copyinfo *next = dirlist->next;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700685 if (!remote_build_list(sc, filelist, dirlist->src, dirlist->dst)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700686 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800687 }
688 free(dirlist);
689 dirlist = next;
690 }
691
Elliott Hughesb628cb12015-08-03 10:38:08 -0700692 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800693}
694
Dan Albertf30d73c2015-02-25 17:51:28 -0800695static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700696{
Greg Hackmann8b689142014-05-06 08:48:18 -0700697 struct utimbuf times = { time, time };
698 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700699
700 /* use umask for permissions */
701 mode_t mask=umask(0000);
702 umask(mask);
703 int r2 = chmod(lpath, mode & ~mask);
704
705 return r1 ? : r2;
706}
707
Elliott Hughesb628cb12015-08-03 10:38:08 -0700708static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
709 int copy_attrs) {
710 // Make sure that both directory paths end in a slash.
711 std::string rpath_clean(rpath);
712 std::string lpath_clean(lpath);
713 if (rpath_clean.empty() || lpath_clean.empty()) return false;
714 if (rpath_clean.back() != '/') rpath_clean.push_back('/');
715 if (lpath_clean.back() != '/') lpath_clean.push_back('/');
Riley Andrewsc736a942014-12-12 13:12:36 -0800716
Elliott Hughesb628cb12015-08-03 10:38:08 -0700717 // Recursively build the list of files to copy.
718 fprintf(stderr, "pull: building file list...\n");
719 copyinfo* filelist = nullptr;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700720 if (!remote_build_list(sc, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700721
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800722 int pulled = 0;
723 int skipped = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700724 copyinfo* ci = filelist;
725 while (ci) {
726 copyinfo* next = ci->next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800727 if (ci->flag == 0) {
728 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700729 if (!sync_recv(sc, ci->src, ci->dst, false)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700730 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800731 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700732
733 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700734 return false;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700735 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800736 pulled++;
737 } else {
738 skipped++;
739 }
740 free(ci);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700741 ci = next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800742 }
743
744 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
745 pulled, (pulled == 1) ? "" : "s",
746 skipped, (skipped == 1) ? "" : "s");
Elliott Hughesb628cb12015-08-03 10:38:08 -0700747 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800748}
749
Elliott Hughesb628cb12015-08-03 10:38:08 -0700750bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
751 SyncConnection sc;
752 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800753
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700754 unsigned mode, time;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700755 if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700756 if (mode == 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700757 fprintf(stderr, "remote object '%s' does not exist\n", rpath);
758 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800759 }
760
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700761 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
762 std::string path_holder;
763 struct stat st;
764 if (stat(lpath, &st) == 0) {
765 if (S_ISDIR(st.st_mode)) {
766 // If we're copying a remote file to a local directory,
767 // we really want to copy to local_dir + "/" + basename(remote).
768 path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
769 lpath = path_holder.c_str();
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800770 }
771 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700772 if (!sync_recv(sc, rpath, lpath, show_progress)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700773 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800774 } else {
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700775 if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700776 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700777 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800778 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700779 return true;
780 } else if (S_ISDIR(mode)) {
781 return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800782 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700783
784 fprintf(stderr, "remote object '%s' not a file or directory\n", rpath);
785 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800786}
787
Elliott Hughesb628cb12015-08-03 10:38:08 -0700788bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesc5a12b22015-04-21 10:17:07 -0700789 fprintf(stderr, "syncing %s...\n", rpath.c_str());
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800790
Elliott Hughesb628cb12015-08-03 10:38:08 -0700791 SyncConnection sc;
792 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800793
Elliott Hughesb628cb12015-08-03 10:38:08 -0700794 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 -0800795}