blob: b7e835ba29fb915d47fa746e7bc7123317b43187 [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>
Elliott Hughes6c73bfc2015-10-27 13:40:35 -070032#include <vector>
Elliott Hughes4e7848d2015-08-24 14:49:43 -070033
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080034#include "sysdeps.h"
Dan Albertb302d122015-02-24 15:51:19 -080035
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080036#include "adb.h"
37#include "adb_client.h"
Dan Albert66a91b02015-02-24 21:26:58 -080038#include "adb_io.h"
Alex Valléee9163152015-05-06 17:22:25 -040039#include "adb_utils.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080040#include "file_sync_service.h"
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070041#include "line_printer.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080042
Elliott Hughesdde00be2015-09-27 12:55:37 -070043#include <base/file.h>
Elliott Hughesb628cb12015-08-03 10:38:08 -070044#include <base/strings.h>
Elliott Hughesd189cfb2015-07-30 17:42:01 -070045#include <base/stringprintf.h>
46
Elliott Hughesb628cb12015-08-03 10:38:08 -070047struct syncsendbuf {
48 unsigned id;
49 unsigned size;
50 char data[SYNC_DATA_MAX];
51};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080052
Elliott Hughesb628cb12015-08-03 10:38:08 -070053class SyncConnection {
54 public:
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070055 SyncConnection() : total_bytes(0), start_time_ms_(CurrentTimeMs()) {
Elliott Hughesb628cb12015-08-03 10:38:08 -070056 max = SYNC_DATA_MAX; // TODO: decide at runtime.
57
58 std::string error;
59 fd = adb_connect("sync:", &error);
60 if (fd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070061 Error("connect failed: %s", error.c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -070062 }
63 }
64
65 ~SyncConnection() {
66 if (!IsValid()) return;
67
68 SendQuit();
Elliott Hughesb628cb12015-08-03 10:38:08 -070069 adb_close(fd);
70 }
71
72 bool IsValid() { return fd >= 0; }
73
Elliott Hughesdde00be2015-09-27 12:55:37 -070074 bool SendRequest(int id, const char* path_and_mode) {
75 size_t path_length = strlen(path_and_mode);
76 if (path_length > 1024) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070077 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -070078 errno = ENAMETOOLONG;
79 return false;
80 }
81
82 // Sending header and payload in a single write makes a noticeable
83 // difference to "adb sync" performance.
Elliott Hughes6c73bfc2015-10-27 13:40:35 -070084 std::vector<char> buf(sizeof(SyncRequest) + path_length);
85 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesdde00be2015-09-27 12:55:37 -070086 req->id = id;
87 req->path_length = path_length;
88 char* data = reinterpret_cast<char*>(req + 1);
89 memcpy(data, path_and_mode, path_length);
90
Elliott Hughes6c73bfc2015-10-27 13:40:35 -070091 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesdde00be2015-09-27 12:55:37 -070092 }
93
94 // Sending header, payload, and footer in a single write makes a huge
95 // difference to "adb sync" performance.
96 bool SendSmallFile(const char* path_and_mode,
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070097 const char* rpath,
Elliott Hughesdde00be2015-09-27 12:55:37 -070098 const char* data, size_t data_length,
99 unsigned mtime) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700100 Print(rpath);
101
Elliott Hughesdde00be2015-09-27 12:55:37 -0700102 size_t path_length = strlen(path_and_mode);
103 if (path_length > 1024) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700104 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700105 errno = ENAMETOOLONG;
106 return false;
107 }
108
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700109 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughesdde00be2015-09-27 12:55:37 -0700110 sizeof(SyncRequest) + data_length +
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700111 sizeof(SyncRequest));
112 char* p = &buf[0];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700113
114 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
115 req_send->id = ID_SEND;
116 req_send->path_length = path_length;
117 p += sizeof(SyncRequest);
118 memcpy(p, path_and_mode, path_length);
119 p += path_length;
120
121 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
122 req_data->id = ID_DATA;
123 req_data->path_length = data_length;
124 p += sizeof(SyncRequest);
125 memcpy(p, data, data_length);
126 p += data_length;
127
128 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
129 req_done->id = ID_DONE;
130 req_done->path_length = mtime;
131 p += sizeof(SyncRequest);
132
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700133 if (!WriteFdExactly(fd, &buf[0], (p - &buf[0]))) return false;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700134
135 total_bytes += data_length;
136 return true;
137 }
138
139 bool CopyDone(const char* from, const char* to) {
140 syncmsg msg;
141 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700142 Error("failed to copy '%s' to '%s': no ID_DONE: %s", from, to, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700143 return false;
144 }
145 if (msg.status.id == ID_OKAY) {
146 return true;
147 }
148 if (msg.status.id != ID_FAIL) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700149 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700150 return false;
151 }
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700152 return ReportCopyFailure(from, to, msg);
153 }
154
155 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700156 std::vector<char> buf(msg.status.msglen + 1);
157 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700158 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
159 from, to, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700160 return false;
161 }
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700162 buf[msg.status.msglen] = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700163 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700164 return false;
165 }
166
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700167 std::string TransferRate() {
168 uint64_t ms = CurrentTimeMs() - start_time_ms_;
169 if (total_bytes == 0 || ms == 0) return "";
170
171 double s = static_cast<double>(ms) / 1000LL;
172 double rate = (static_cast<double>(total_bytes) / s) / (1024*1024);
173 return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
174 rate, total_bytes, s);
175 }
176
177 void Print(const std::string& s) {
178 // TODO: we actually don't want ELIDE; we want "ELIDE if smart, FULL if dumb".
179 line_printer_.Print(s, LinePrinter::ELIDE);
180 }
181
182 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
183 std::string s = "adb: error: ";
184
185 va_list ap;
186 va_start(ap, fmt);
187 android::base::StringAppendV(&s, fmt, ap);
188 va_end(ap);
189
190 line_printer_.Print(s, LinePrinter::FULL);
191 }
192
Elliott Hughesb628cb12015-08-03 10:38:08 -0700193 uint64_t total_bytes;
194
195 // TODO: add a char[max] buffer here, to replace syncsendbuf...
196 int fd;
197 size_t max;
198
199 private:
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700200 uint64_t start_time_ms_;
201
202 LinePrinter line_printer_;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700203
204 void SendQuit() {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700205 SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesb628cb12015-08-03 10:38:08 -0700206 }
207
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700208 static uint64_t CurrentTimeMs() {
209 struct timeval tv;
210 gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
211 return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700212 }
213};
214
215typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
216
Elliott Hughesdde00be2015-09-27 12:55:37 -0700217static bool sync_ls(SyncConnection& sc, const char* path, sync_ls_cb func, void* cookie) {
218 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700219
220 while (true) {
221 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700222 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700223
224 if (msg.dent.id == ID_DONE) return true;
225 if (msg.dent.id != ID_DENT) return false;
226
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700227 size_t len = msg.dent.namelen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700228 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800229
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700230 char buf[257];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700231 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800232 buf[len] = 0;
233
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700234 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf, cookie);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800235 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800236}
237
Elliott Hughesb628cb12015-08-03 10:38:08 -0700238static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
239 unsigned int* mode, unsigned int* size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800240 syncmsg msg;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700241 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
242 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800243 }
244
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700245 if (timestamp) *timestamp = msg.stat.time;
246 if (mode) *mode = msg.stat.mode;
247 if (size) *size = msg.stat.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800248
Elliott Hughesb628cb12015-08-03 10:38:08 -0700249 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800250}
251
Elliott Hughesb628cb12015-08-03 10:38:08 -0700252static bool sync_stat(SyncConnection& sc, const char* path,
253 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700254 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800255}
256
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700257static bool SendLargeFile(SyncConnection& sc, const char* path_and_mode,
258 const char* lpath, const char* rpath,
259 unsigned mtime) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700260 if (!sc.SendRequest(ID_SEND, path_and_mode)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700261 sc.Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700262 return false;
263 }
264
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700265 struct stat st;
266 if (stat(lpath, &st) == -1) {
267 sc.Error("cannot stat '%s': %s", lpath, strerror(errno));
268 return false;
Spencer Lowc1a31332015-08-28 01:07:30 -0700269 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800270
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700271 uint64_t total_size = st.st_size;
272 uint64_t bytes_copied = 0;
273
274 int lfd = adb_open(lpath, O_RDONLY);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700275 if (lfd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700276 sc.Error("cannot open '%s': %s", lpath, strerror(errno));
Spencer Lowc1a31332015-08-28 01:07:30 -0700277 return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700278 }
279
Elliott Hughesdde00be2015-09-27 12:55:37 -0700280 syncsendbuf sbuf;
281 sbuf.id = ID_DATA;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700282 while (true) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700283 int ret = adb_read(lfd, sbuf.data, sc.max);
Elliott Hughes0bd85872015-08-25 10:59:45 -0700284 if (ret <= 0) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700285 if (ret < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700286 sc.Error("cannot read '%s': %s", lpath, strerror(errno));
Spencer Lowc1a31332015-08-28 01:07:30 -0700287 adb_close(lfd);
288 return false;
289 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800290 break;
291 }
292
Elliott Hughesdde00be2015-09-27 12:55:37 -0700293 sbuf.size = ret;
294 if (!WriteFdExactly(sc.fd, &sbuf, sizeof(unsigned) * 2 + ret)) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700295 adb_close(lfd);
296 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800297 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700298 sc.total_bytes += ret;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700299
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700300 bytes_copied += ret;
301
302 int percentage = static_cast<int>(bytes_copied * 100 / total_size);
303 sc.Print(android::base::StringPrintf("%s: %d%%", rpath, percentage));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800304 }
305
306 adb_close(lfd);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800307
Elliott Hughesb628cb12015-08-03 10:38:08 -0700308 syncmsg msg;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800309 msg.data.id = ID_DONE;
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700310 msg.data.size = mtime;
Elliott Hughesc5d51622015-09-03 11:06:00 -0700311 if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700312 sc.Error("failed to send ID_DONE message for '%s': %s", rpath, strerror(errno));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700313 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800314 }
315
Elliott Hughesb628cb12015-08-03 10:38:08 -0700316 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800317}
318
Elliott Hughesdde00be2015-09-27 12:55:37 -0700319static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700320 unsigned mtime, mode_t mode)
Elliott Hughesdde00be2015-09-27 12:55:37 -0700321{
322 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
323
324 if (S_ISLNK(mode)) {
325#if !defined(_WIN32)
326 char buf[PATH_MAX];
327 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
328 if (data_length == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700329 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700330 return false;
331 }
332 buf[data_length++] = '\0';
333
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700334 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, buf, data_length, mtime)) return false;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700335 return sc.CopyDone(lpath, rpath);
336#endif
337 }
338
339 if (!S_ISREG(mode)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700340 sc.Error("local file '%s' has unsupported mode: 0o%o", lpath, mode);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700341 return false;
342 }
343
344 struct stat st;
345 if (stat(lpath, &st) == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700346 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700347 return false;
348 }
349 if (st.st_size < SYNC_DATA_MAX) {
350 std::string data;
351 if (!android::base::ReadFileToString(lpath, &data)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700352 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700353 return false;
354 }
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700355 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, data.data(), data.size(), mtime)) {
356 return false;
357 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700358 } else {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700359 if (!SendLargeFile(sc, path_and_mode.c_str(), lpath, rpath, mtime)) {
360 return false;
361 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700362 }
363 return sc.CopyDone(lpath, rpath);
364}
365
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700366static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
367 sc.Print(rpath);
368
Elliott Hughesb628cb12015-08-03 10:38:08 -0700369 unsigned size = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700370 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700371
Elliott Hughesdde00be2015-09-27 12:55:37 -0700372 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800373
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700374 adb_unlink(lpath);
375 mkdirs(lpath);
376 int lfd = adb_creat(lpath, 0644);
377 if (lfd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700378 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700379 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800380 }
381
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700382 uint64_t bytes_copied = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700383 while (true) {
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700384 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700385 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700386 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700387 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700388 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800389 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800390
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700391 if (msg.data.id == ID_DONE) break;
392
393 if (msg.data.id != ID_DATA) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800394 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700395 adb_unlink(lpath);
396 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700397 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800398 }
399
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700400 if (msg.data.size > sc.max) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700401 sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800402 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700403 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700404 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800405 }
406
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700407 char buffer[SYNC_DATA_MAX];
408 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800409 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700410 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700411 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800412 }
413
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700414 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700415 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700416 adb_close(lfd);
417 adb_unlink(lpath);
418 return false;
419 }
420
421 sc.total_bytes += msg.data.size;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700422
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700423 bytes_copied += msg.data.size;
424
425 int percentage = static_cast<int>(bytes_copied * 100 / size);
426 sc.Print(android::base::StringPrintf("%s: %d%%", rpath, percentage));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800427 }
428
429 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700430 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800431}
432
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800433static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
Elliott Hughesb628cb12015-08-03 10:38:08 -0700434 const char* name, void* /*cookie*/) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800435 printf("%08x %08x %08x %s\n", mode, size, time, name);
436}
437
Elliott Hughesb628cb12015-08-03 10:38:08 -0700438bool do_sync_ls(const char* path) {
439 SyncConnection sc;
440 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800441
Elliott Hughesdde00be2015-09-27 12:55:37 -0700442 return sync_ls(sc, path, do_sync_ls_cb, 0);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800443}
444
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800445struct copyinfo
446{
447 copyinfo *next;
448 const char *src;
449 const char *dst;
450 unsigned int time;
451 unsigned int mode;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700452 uint64_t size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800453 int flag;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800454};
455
Elliott Hughes712416a2015-05-05 18:26:10 -0700456static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800457 int slen = strlen(spath);
458 int dlen = strlen(dpath);
459 int nlen = strlen(name);
460 int ssize = slen + nlen + 2;
461 int dsize = dlen + nlen + 2;
462
Elliott Hughes712416a2015-05-05 18:26:10 -0700463 copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700464 if (ci == 0) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700465 fprintf(stderr, "out of memory\n");
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800466 abort();
467 }
468
469 ci->next = 0;
470 ci->time = 0;
471 ci->mode = 0;
472 ci->size = 0;
473 ci->flag = 0;
474 ci->src = (const char*)(ci + 1);
475 ci->dst = ci->src + ssize;
476 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
477 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
478
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800479 return ci;
480}
481
Elliott Hughesb628cb12015-08-03 10:38:08 -0700482static bool IsDotOrDotDot(const char* name) {
483 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
484}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800485
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700486static int local_build_list(SyncConnection& sc,
487 copyinfo** filelist, const char* lpath, const char* rpath) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800488 copyinfo *dirlist = 0;
489 copyinfo *ci, *next;
490
Elliott Hughesb628cb12015-08-03 10:38:08 -0700491 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
492 if (!dir) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700493 sc.Error("cannot open '%s': %s", lpath, strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800494 return -1;
495 }
496
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700497 dirent* de;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700498 while ((de = readdir(dir.get()))) {
499 if (IsDotOrDotDot(de->d_name)) continue;
500
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800501 char stat_path[PATH_MAX];
Elliott Hughesb628cb12015-08-03 10:38:08 -0700502 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700503 sc.Error("skipping long path '%s%s'", lpath, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800504 continue;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700505 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800506 strcpy(stat_path, lpath);
507 strcat(stat_path, de->d_name);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800508
Elliott Hughesb628cb12015-08-03 10:38:08 -0700509 struct stat st;
510 if (!lstat(stat_path, &st)) {
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700511 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700512 ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700513 ci->next = dirlist;
514 dirlist = ci;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800515 } else {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700516 ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
517 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700518 sc.Error("skipping special file '%s'", ci->src);
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700519 free(ci);
520 } else {
521 ci->time = st.st_mtime;
522 ci->mode = st.st_mode;
523 ci->size = st.st_size;
524 ci->next = *filelist;
525 *filelist = ci;
526 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800527 }
Daniel Rosenberge9a1c9c2014-06-30 20:29:40 -0700528 } else {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700529 sc.Error("cannot lstat '%s': %s",stat_path , strerror(errno));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800530 }
531 }
532
Elliott Hughesb628cb12015-08-03 10:38:08 -0700533 // Close this directory and recurse.
534 dir.reset();
535 for (ci = dirlist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800536 next = ci->next;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700537 local_build_list(sc, filelist, ci->src, ci->dst);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800538 free(ci);
539 }
540
541 return 0;
542}
543
Elliott Hughesb628cb12015-08-03 10:38:08 -0700544static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
545 bool check_timestamps, bool list_only) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800546 copyinfo *filelist = 0;
547 copyinfo *ci, *next;
548 int pushed = 0;
549 int skipped = 0;
550
Elliott Hughesb628cb12015-08-03 10:38:08 -0700551 if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
552 if (lpath[strlen(lpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800553 int tmplen = strlen(lpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800554 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700555 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800556 snprintf(tmp, tmplen, "%s/",lpath);
557 lpath = tmp;
558 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700559 if (rpath[strlen(rpath) - 1] != '/') {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800560 int tmplen = strlen(rpath)+2;
Dan Albertf30d73c2015-02-25 17:51:28 -0800561 char *tmp = reinterpret_cast<char*>(malloc(tmplen));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700562 if(tmp == 0) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800563 snprintf(tmp, tmplen, "%s/",rpath);
564 rpath = tmp;
565 }
566
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700567 if (local_build_list(sc, &filelist, lpath, rpath)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700568 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800569 }
570
Elliott Hughesb628cb12015-08-03 10:38:08 -0700571 if (check_timestamps) {
572 for (ci = filelist; ci != 0; ci = ci->next) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700573 if (!sc.SendRequest(ID_STAT, ci->dst)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800574 }
575 for(ci = filelist; ci != 0; ci = ci->next) {
576 unsigned int timestamp, mode, size;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700577 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
578 if (size == ci->size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800579 /* for links, we cannot update the atime/mtime */
Elliott Hughesb628cb12015-08-03 10:38:08 -0700580 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
581 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800582 ci->flag = 1;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700583 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800584 }
585 }
586 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700587 for (ci = filelist; ci != 0; ci = next) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800588 next = ci->next;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700589 if (ci->flag == 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700590 if (list_only) {
591 fprintf(stderr, "would push: %s -> %s\n", ci->src, ci->dst);
592 } else {
593 if (!sync_send(sc, ci->src, ci->dst, ci->time, ci->mode)) {
594 return false;
595 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800596 }
597 pushed++;
598 } else {
599 skipped++;
600 }
601 free(ci);
602 }
603
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700604 sc.Print(android::base::StringPrintf("%s: %d file%s pushed. %d file%s skipped.%s\n",
605 rpath,
606 pushed, (pushed == 1) ? "" : "s",
607 skipped, (skipped == 1) ? "" : "s",
608 sc.TransferRate().c_str()));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700609 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800610}
611
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700612bool do_sync_push(const char* lpath, const char* rpath) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700613 SyncConnection sc;
614 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800615
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700616 struct stat st;
617 if (stat(lpath, &st)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700618 sc.Error("cannot stat '%s': %s", lpath, strerror(errno));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700619 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800620 }
621
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700622 if (S_ISDIR(st.st_mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700623 return copy_local_dir_remote(sc, lpath, rpath, false, false);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800624 }
625
Elliott Hughesb628cb12015-08-03 10:38:08 -0700626 unsigned mode;
627 if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
628 std::string path_holder;
629 if (mode != 0 && S_ISDIR(mode)) {
630 // If we're copying a local file to a remote directory,
631 // we really want to copy to remote_dir + "/" + local_filename.
632 path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
633 rpath = path_holder.c_str();
634 }
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700635 bool result = sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode);
636 sc.Print("\n");
637 return result;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800638}
639
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700640struct sync_ls_build_list_cb_args {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700641 SyncConnection* sc;
642 copyinfo** filelist;
643 copyinfo** dirlist;
644 const char* rpath;
645 const char* lpath;
Elliott Hughesfe7ff812015-04-17 09:47:42 -0700646};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800647
Elliott Hughes712416a2015-05-05 18:26:10 -0700648static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
649 const char* name, void* cookie)
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800650{
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700651 sync_ls_build_list_cb_args* args = static_cast<sync_ls_build_list_cb_args*>(cookie);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800652 copyinfo *ci;
653
654 if (S_ISDIR(mode)) {
655 copyinfo **dirlist = args->dirlist;
656
Elliott Hughesb628cb12015-08-03 10:38:08 -0700657 // Don't try recursing down "." or "..".
658 if (IsDotOrDotDot(name)) return;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800659
660 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
661 ci->next = *dirlist;
662 *dirlist = ci;
663 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
664 copyinfo **filelist = args->filelist;
665
666 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
667 ci->time = time;
668 ci->mode = mode;
669 ci->size = size;
670 ci->next = *filelist;
671 *filelist = ci;
672 } else {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700673 args->sc->Print(android::base::StringPrintf("skipping special file '%s'\n", name));
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800674 }
675}
676
Elliott Hughesdde00be2015-09-27 12:55:37 -0700677static bool remote_build_list(SyncConnection& sc, copyinfo **filelist,
Elliott Hughesb628cb12015-08-03 10:38:08 -0700678 const char *rpath, const char *lpath) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700679 copyinfo* dirlist = nullptr;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800680
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700681 sync_ls_build_list_cb_args args;
682 args.sc = &sc;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800683 args.filelist = filelist;
684 args.dirlist = &dirlist;
685 args.rpath = rpath;
686 args.lpath = lpath;
687
Elliott Hughesb628cb12015-08-03 10:38:08 -0700688 // Put the files/dirs in rpath on the lists.
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700689 if (!sync_ls(sc, rpath, sync_ls_build_list_cb, &args)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700690 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800691 }
692
Elliott Hughesb628cb12015-08-03 10:38:08 -0700693 // Recurse into each directory we found.
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800694 while (dirlist != NULL) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700695 copyinfo* next = dirlist->next;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700696 if (!remote_build_list(sc, filelist, dirlist->src, dirlist->dst)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700697 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800698 }
699 free(dirlist);
700 dirlist = next;
701 }
702
Elliott Hughesb628cb12015-08-03 10:38:08 -0700703 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800704}
705
Dan Albertf30d73c2015-02-25 17:51:28 -0800706static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700707{
Greg Hackmann8b689142014-05-06 08:48:18 -0700708 struct utimbuf times = { time, time };
709 int r1 = utime(lpath, &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700710
711 /* use umask for permissions */
712 mode_t mask=umask(0000);
713 umask(mask);
714 int r2 = chmod(lpath, mode & ~mask);
715
716 return r1 ? : r2;
717}
718
Elliott Hughesb628cb12015-08-03 10:38:08 -0700719static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
720 int copy_attrs) {
721 // Make sure that both directory paths end in a slash.
722 std::string rpath_clean(rpath);
723 std::string lpath_clean(lpath);
724 if (rpath_clean.empty() || lpath_clean.empty()) return false;
725 if (rpath_clean.back() != '/') rpath_clean.push_back('/');
726 if (lpath_clean.back() != '/') lpath_clean.push_back('/');
Riley Andrewsc736a942014-12-12 13:12:36 -0800727
Elliott Hughesb628cb12015-08-03 10:38:08 -0700728 // Recursively build the list of files to copy.
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700729 sc.Print("pull: building file list...");
Elliott Hughesb628cb12015-08-03 10:38:08 -0700730 copyinfo* filelist = nullptr;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700731 if (!remote_build_list(sc, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700732
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800733 int pulled = 0;
734 int skipped = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700735 copyinfo* ci = filelist;
736 while (ci) {
737 copyinfo* next = ci->next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800738 if (ci->flag == 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700739 sc.Print(android::base::StringPrintf("pull: %s -> %s", ci->src, ci->dst));
740 if (!sync_recv(sc, ci->src, ci->dst)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700741 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800742 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700743
744 if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700745 return false;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700746 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800747 pulled++;
748 } else {
749 skipped++;
750 }
751 free(ci);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700752 ci = next;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800753 }
754
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700755 sc.Print(android::base::StringPrintf("%s: %d file%s pulled. %d file%s skipped.%s\n",
756 rpath,
757 pulled, (pulled == 1) ? "" : "s",
758 skipped, (skipped == 1) ? "" : "s",
759 sc.TransferRate().c_str()));
Elliott Hughesb628cb12015-08-03 10:38:08 -0700760 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800761}
762
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700763bool do_sync_pull(const char* rpath, const char* lpath, int copy_attrs) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700764 SyncConnection sc;
765 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800766
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700767 unsigned mode, time;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700768 if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700769 if (mode == 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700770 sc.Error("remote object '%s' does not exist", rpath);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700771 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800772 }
773
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700774 if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
775 std::string path_holder;
776 struct stat st;
777 if (stat(lpath, &st) == 0) {
778 if (S_ISDIR(st.st_mode)) {
779 // If we're copying a remote file to a local directory,
780 // we really want to copy to local_dir + "/" + basename(remote).
781 path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
782 lpath = path_holder.c_str();
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800783 }
784 }
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700785 if (!sync_recv(sc, rpath, lpath)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700786 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800787 } else {
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700788 if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700789 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700790 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800791 }
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700792 sc.Print("\n");
Elliott Hughesb628cb12015-08-03 10:38:08 -0700793 return true;
794 } else if (S_ISDIR(mode)) {
795 return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800796 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700797
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700798 sc.Error("remote object '%s' not a file or directory", rpath);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700799 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800800}
801
Elliott Hughesb628cb12015-08-03 10:38:08 -0700802bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700803 SyncConnection sc;
804 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800805
Elliott Hughesb628cb12015-08-03 10:38:08 -0700806 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 -0800807}