blob: 26f8d831cae5e206c5ca4bcfea2d38b1978cb513 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-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 Albert76649012015-02-24 15:51:19 -080017#include <dirent.h>
Spencer Low6001c872015-05-13 00:02:55 -070018#include <inttypes.h>
Dan Albert76649012015-02-24 15:51:19 -080019#include <limits.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080020#include <stdio.h>
21#include <stdlib.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080022#include <sys/stat.h>
23#include <sys/time.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080024#include <sys/types.h>
Dan Albert76649012015-02-24 15:51:19 -080025#include <time.h>
Elliott Hughesae5a6c02015-09-27 12:55:37 -070026#include <unistd.h>
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -070027#include <utime.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080028
Josh Gaofb0c5cb2016-08-04 14:53:17 -070029#include <chrono>
Josh Gaocda6a2b2015-11-02 16:45:47 -080030#include <functional>
Elliott Hughesa925dba2015-08-24 14:49:43 -070031#include <memory>
Josh Gaofb0c5cb2016-08-04 14:53:17 -070032#include <sstream>
33#include <string>
Elliott Hughes6d929972015-10-27 13:40:35 -070034#include <vector>
Elliott Hughesa925dba2015-08-24 14:49:43 -070035
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036#include "sysdeps.h"
Dan Albert76649012015-02-24 15:51:19 -080037
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080038#include "adb.h"
39#include "adb_client.h"
Dan Albertcc731cc2015-02-24 21:26:58 -080040#include "adb_io.h"
Alex Vallée14216142015-05-06 17:22:25 -040041#include "adb_utils.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080042#include "file_sync_service.h"
Elliott Hughesb708d162015-10-27 16:03:15 -070043#include "line_printer.h"
Josh Gao5a1e3fd2016-12-05 17:11:34 -080044#include "sysdeps/errno.h"
Josh Gao05a3abf2016-11-18 15:17:07 -080045#include "sysdeps/stat.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080046
Elliott Hughes4f713192015-12-04 22:00:26 -080047#include <android-base/file.h>
48#include <android-base/strings.h>
49#include <android-base/stringprintf.h>
Elliott Hughes5c742702015-07-30 17:42:01 -070050
Elliott Hughesaa245492015-08-03 10:38:08 -070051struct syncsendbuf {
52 unsigned id;
53 unsigned size;
54 char data[SYNC_DATA_MAX];
55};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080056
Elliott Hughesa00e6ef2015-12-17 17:05:29 -080057static void ensure_trailing_separators(std::string& local_path, std::string& remote_path) {
58 if (!adb_is_separator(local_path.back())) {
59 local_path.push_back(OS_PATH_SEPARATOR);
60 }
61 if (remote_path.back() != '/') {
62 remote_path.push_back('/');
63 }
64}
65
Josh Gao48bc0d72016-03-02 16:11:13 -080066static bool should_pull_file(mode_t mode) {
Josh Gao05a3abf2016-11-18 15:17:07 -080067 return S_ISREG(mode) || S_ISBLK(mode) || S_ISCHR(mode);
Josh Gao48bc0d72016-03-02 16:11:13 -080068}
69
70static bool should_push_file(mode_t mode) {
Josh Gao05a3abf2016-11-18 15:17:07 -080071 return S_ISREG(mode) || S_ISLNK(mode);
Josh Gao48bc0d72016-03-02 16:11:13 -080072}
73
Elliott Hughesa00e6ef2015-12-17 17:05:29 -080074struct copyinfo {
75 std::string lpath;
76 std::string rpath;
Josh Gao5a1e3fd2016-12-05 17:11:34 -080077 int64_t time = 0;
78 uint32_t mode;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -080079 uint64_t size = 0;
80 bool skip = false;
81
82 copyinfo(const std::string& local_path,
83 const std::string& remote_path,
84 const std::string& name,
85 unsigned int mode)
86 : lpath(local_path), rpath(remote_path), mode(mode) {
87 ensure_trailing_separators(lpath, rpath);
88 lpath.append(name);
89 rpath.append(name);
90 if (S_ISDIR(mode)) {
91 ensure_trailing_separators(lpath, rpath);
92 }
93 }
94};
95
Josh Gaofb0c5cb2016-08-04 14:53:17 -070096enum class TransferDirection {
97 push,
98 pull,
99};
100
101struct TransferLedger {
102 std::chrono::steady_clock::time_point start_time;
103 uint64_t files_transferred;
104 uint64_t files_skipped;
105 uint64_t bytes_transferred;
106 uint64_t bytes_expected;
107 bool expect_multiple_files;
108
109 TransferLedger() {
110 Reset();
111 }
112
113 bool operator==(const TransferLedger& other) const {
114 return files_transferred == other.files_transferred &&
115 files_skipped == other.files_skipped && bytes_transferred == other.bytes_transferred;
116 }
117
118 bool operator!=(const TransferLedger& other) const {
119 return !(*this == other);
120 }
121
122 void Reset() {
123 start_time = std::chrono::steady_clock::now();
124 files_transferred = 0;
125 files_skipped = 0;
126 bytes_transferred = 0;
127 bytes_expected = 0;
128 }
129
130 std::string TransferRate() {
131 if (bytes_transferred == 0) return "";
132
133 std::chrono::duration<double> duration;
134 duration = std::chrono::steady_clock::now() - start_time;
135
136 double s = duration.count();
137 if (s == 0) {
138 return "";
139 }
140 double rate = (static_cast<double>(bytes_transferred) / s) / (1024 * 1024);
141 return android::base::StringPrintf(" %.1f MB/s (%" PRIu64 " bytes in %.3fs)", rate,
142 bytes_transferred, s);
143 }
144
145 void ReportProgress(LinePrinter& lp, const std::string& file, uint64_t file_copied_bytes,
146 uint64_t file_total_bytes) {
147 char overall_percentage_str[5] = "?";
Josh Gaoda1f2792016-11-17 16:02:36 -0800148 if (bytes_expected != 0 && bytes_transferred <= bytes_expected) {
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700149 int overall_percentage = static_cast<int>(bytes_transferred * 100 / bytes_expected);
150 // If we're pulling symbolic links, we'll pull the target of the link rather than
151 // just create a local link, and that will cause us to go over 100%.
152 if (overall_percentage <= 100) {
153 snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
154 overall_percentage);
155 }
156 }
157
158 std::string output;
159 if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
160 // This case can happen if we're racing against something that wrote to the file
161 // between our stat and our read, or if we're reading a magic file that lies about
162 // its size. Just show how much we've copied.
163 output = android::base::StringPrintf("[%4s] %s: %" PRId64 "/?", overall_percentage_str,
164 file.c_str(), file_copied_bytes);
165 } else {
166 // If we're transferring multiple files, we want to know how far through the current
167 // file we are, as well as the overall percentage.
168 if (expect_multiple_files) {
169 int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
170 output = android::base::StringPrintf("[%4s] %s: %d%%", overall_percentage_str,
171 file.c_str(), file_percentage);
172 } else {
173 output =
174 android::base::StringPrintf("[%4s] %s", overall_percentage_str, file.c_str());
175 }
176 }
177 lp.Print(output, LinePrinter::LineType::INFO);
178 }
179
180 void ReportTransferRate(LinePrinter& lp, const std::string& name, TransferDirection direction) {
181 const char* direction_str = (direction == TransferDirection::push) ? "pushed" : "pulled";
182 std::stringstream ss;
183 if (!name.empty()) {
184 ss << name << ": ";
185 }
186 ss << files_transferred << " file" << ((files_transferred == 1) ? "" : "s") << " "
187 << direction_str << ".";
188 if (files_skipped > 0) {
189 ss << " " << files_skipped << " file" << ((files_skipped == 1) ? "" : "s")
190 << " skipped.";
191 }
192 ss << TransferRate();
193
194 lp.Print(ss.str(), LinePrinter::LineType::INFO);
195 lp.KeepInfoLine();
196 }
197};
198
Elliott Hughesaa245492015-08-03 10:38:08 -0700199class SyncConnection {
200 public:
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700201 SyncConnection() : expect_done_(false) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700202 max = SYNC_DATA_MAX; // TODO: decide at runtime.
203
204 std::string error;
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800205 FeatureSet features;
206 if (!adb_get_feature_set(&features, &error)) {
207 fd = -1;
208 Error("failed to get feature set: %s", error.c_str());
209 } else {
210 have_stat_v2_ = CanUseFeature(features, kFeatureStat2);
211 fd = adb_connect("sync:", &error);
212 if (fd < 0) {
213 Error("connect failed: %s", error.c_str());
214 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700215 }
216 }
217
218 ~SyncConnection() {
219 if (!IsValid()) return;
220
Spencer Low351ecd12015-10-14 17:32:44 -0700221 if (SendQuit()) {
222 // We sent a quit command, so the server should be doing orderly
223 // shutdown soon. But if we encountered an error while we were using
224 // the connection, the server might still be sending data (before
225 // doing orderly shutdown), in which case we won't wait for all of
226 // the data nor the coming orderly shutdown. In the common success
227 // case, this will wait for the server to do orderly shutdown.
228 ReadOrderlyShutdown(fd);
229 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700230 adb_close(fd);
Elliott Hughes77f539a2015-12-08 16:01:15 -0800231
232 line_printer_.KeepInfoLine();
Elliott Hughesaa245492015-08-03 10:38:08 -0700233 }
234
235 bool IsValid() { return fd >= 0; }
236
Josh Gaoda811952016-02-19 15:55:55 -0800237 bool ReceivedError(const char* from, const char* to) {
238 adb_pollfd pfd = {.fd = fd, .events = POLLIN};
239 int rc = adb_poll(&pfd, 1, 0);
240 if (rc < 0) {
241 Error("failed to poll: %s", strerror(errno));
242 return true;
243 }
244 return rc != 0;
245 }
246
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700247 void NewTransfer() {
248 current_ledger_.Reset();
249 }
250
251 void RecordBytesTransferred(size_t bytes) {
252 current_ledger_.bytes_transferred += bytes;
253 global_ledger_.bytes_transferred += bytes;
254 }
255
256 void RecordFilesTransferred(size_t files) {
257 current_ledger_.files_transferred += files;
258 global_ledger_.files_transferred += files;
259 }
260
261 void RecordFilesSkipped(size_t files) {
262 current_ledger_.files_skipped += files;
263 global_ledger_.files_skipped += files;
264 }
265
266 void ReportProgress(const std::string& file, uint64_t file_copied_bytes,
267 uint64_t file_total_bytes) {
268 current_ledger_.ReportProgress(line_printer_, file, file_copied_bytes, file_total_bytes);
269 }
270
271 void ReportTransferRate(const std::string& file, TransferDirection direction) {
272 current_ledger_.ReportTransferRate(line_printer_, file, direction);
273 }
274
275 void ReportOverallTransferRate(TransferDirection direction) {
276 if (current_ledger_ != global_ledger_) {
277 global_ledger_.ReportTransferRate(line_printer_, "", direction);
278 }
279 }
280
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700281 bool SendRequest(int id, const char* path_and_mode) {
282 size_t path_length = strlen(path_and_mode);
283 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700284 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700285 errno = ENAMETOOLONG;
286 return false;
287 }
288
289 // Sending header and payload in a single write makes a noticeable
290 // difference to "adb sync" performance.
Elliott Hughes6d929972015-10-27 13:40:35 -0700291 std::vector<char> buf(sizeof(SyncRequest) + path_length);
292 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700293 req->id = id;
294 req->path_length = path_length;
295 char* data = reinterpret_cast<char*>(req + 1);
296 memcpy(data, path_and_mode, path_length);
297
Elliott Hughes6d929972015-10-27 13:40:35 -0700298 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700299 }
300
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800301 bool SendStat(const char* path_and_mode) {
302 if (!have_stat_v2_) {
303 errno = ENOTSUP;
304 return false;
305 }
306 return SendRequest(ID_STAT_V2, path_and_mode);
307 }
308
309 bool SendLstat(const char* path_and_mode) {
310 if (have_stat_v2_) {
311 return SendRequest(ID_LSTAT_V2, path_and_mode);
312 } else {
313 return SendRequest(ID_LSTAT_V1, path_and_mode);
314 }
315 }
316
317 bool FinishStat(struct stat* st) {
318 syncmsg msg;
319
320 memset(st, 0, sizeof(*st));
321 if (have_stat_v2_) {
322 if (!ReadFdExactly(fd, &msg.stat_v2, sizeof(msg.stat_v2))) {
323 fatal_errno("protocol fault: failed to read stat response");
324 }
325
326 if (msg.stat_v2.id != ID_LSTAT_V2 && msg.stat_v2.id != ID_STAT_V2) {
327 fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32,
328 msg.stat_v2.id);
329 }
330
331 if (msg.stat_v2.error != 0) {
332 errno = errno_from_wire(msg.stat_v2.error);
333 return false;
334 }
335
336 st->st_dev = msg.stat_v2.dev;
337 st->st_ino = msg.stat_v2.ino;
338 st->st_mode = msg.stat_v2.mode;
339 st->st_nlink = msg.stat_v2.nlink;
340 st->st_uid = msg.stat_v2.uid;
341 st->st_gid = msg.stat_v2.gid;
342 st->st_size = msg.stat_v2.size;
343 st->st_atime = msg.stat_v2.atime;
344 st->st_mtime = msg.stat_v2.mtime;
345 st->st_ctime = msg.stat_v2.ctime;
346 return true;
347 } else {
348 if (!ReadFdExactly(fd, &msg.stat_v1, sizeof(msg.stat_v1))) {
349 fatal_errno("protocol fault: failed to read stat response");
350 }
351
352 if (msg.stat_v1.id != ID_LSTAT_V1) {
353 fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32,
354 msg.stat_v1.id);
355 }
356
357 if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) {
358 // There's no way for us to know what the error was.
359 errno = ENOPROTOOPT;
360 return false;
361 }
362
363 st->st_mode = msg.stat_v1.mode;
364 st->st_size = msg.stat_v1.size;
365 st->st_ctime = msg.stat_v1.time;
366 st->st_mtime = msg.stat_v1.time;
367 }
368
369 return true;
370 }
371
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700372 // Sending header, payload, and footer in a single write makes a huge
373 // difference to "adb sync" performance.
374 bool SendSmallFile(const char* path_and_mode,
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800375 const char* lpath, const char* rpath,
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800376 unsigned mtime,
377 const char* data, size_t data_length) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700378 size_t path_length = strlen(path_and_mode);
379 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700380 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700381 errno = ENAMETOOLONG;
382 return false;
383 }
384
Elliott Hughes6d929972015-10-27 13:40:35 -0700385 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800386 sizeof(SyncRequest) + data_length +
387 sizeof(SyncRequest));
Elliott Hughes6d929972015-10-27 13:40:35 -0700388 char* p = &buf[0];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700389
390 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
391 req_send->id = ID_SEND;
392 req_send->path_length = path_length;
393 p += sizeof(SyncRequest);
394 memcpy(p, path_and_mode, path_length);
395 p += path_length;
396
397 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
398 req_data->id = ID_DATA;
399 req_data->path_length = data_length;
400 p += sizeof(SyncRequest);
401 memcpy(p, data, data_length);
402 p += data_length;
403
404 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
405 req_done->id = ID_DONE;
406 req_done->path_length = mtime;
407 p += sizeof(SyncRequest);
408
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800409 WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
Josh Gaoda811952016-02-19 15:55:55 -0800410 expect_done_ = true;
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700411
412 // RecordFilesTransferred gets called in CopyDone.
413 RecordBytesTransferred(data_length);
Josh Gaof22bc602016-03-01 11:46:02 -0800414 ReportProgress(rpath, data_length, data_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700415 return true;
416 }
417
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800418 bool SendLargeFile(const char* path_and_mode,
419 const char* lpath, const char* rpath,
420 unsigned mtime) {
421 if (!SendRequest(ID_SEND, path_and_mode)) {
422 Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
423 return false;
424 }
425
426 struct stat st;
427 if (stat(lpath, &st) == -1) {
428 Error("cannot stat '%s': %s", lpath, strerror(errno));
429 return false;
430 }
431
432 uint64_t total_size = st.st_size;
433 uint64_t bytes_copied = 0;
434
435 int lfd = adb_open(lpath, O_RDONLY);
436 if (lfd < 0) {
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800437 Error("opening '%s' locally failed: %s", lpath, strerror(errno));
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800438 return false;
439 }
440
441 syncsendbuf sbuf;
442 sbuf.id = ID_DATA;
443 while (true) {
Jerry Zhangecee4342017-07-18 14:07:57 -0700444 int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800445 if (bytes_read == -1) {
446 Error("reading '%s' locally failed: %s", lpath, strerror(errno));
447 adb_close(lfd);
448 return false;
449 } else if (bytes_read == 0) {
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800450 break;
451 }
452
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800453 sbuf.size = bytes_read;
454 WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800455
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700456 RecordBytesTransferred(bytes_read);
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800457 bytes_copied += bytes_read;
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800458
Josh Gaoda811952016-02-19 15:55:55 -0800459 // Check to see if we've received an error from the other side.
460 if (ReceivedError(lpath, rpath)) {
461 break;
462 }
463
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800464 ReportProgress(rpath, bytes_copied, total_size);
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800465 }
466
467 adb_close(lfd);
468
469 syncmsg msg;
470 msg.data.id = ID_DONE;
471 msg.data.size = mtime;
Josh Gaoda811952016-02-19 15:55:55 -0800472 expect_done_ = true;
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700473
474 // RecordFilesTransferred gets called in CopyDone.
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800475 return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800476 }
477
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700478 bool CopyDone(const char* from, const char* to) {
479 syncmsg msg;
480 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Josh Gaoda811952016-02-19 15:55:55 -0800481 Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700482 return false;
483 }
484 if (msg.status.id == ID_OKAY) {
Josh Gaoda811952016-02-19 15:55:55 -0800485 if (expect_done_) {
486 expect_done_ = false;
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700487 RecordFilesTransferred(1);
Josh Gaoda811952016-02-19 15:55:55 -0800488 return true;
489 } else {
490 Error("failed to copy '%s' to '%s': received premature success", from, to);
491 return true;
492 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700493 }
494 if (msg.status.id != ID_FAIL) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700495 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700496 return false;
497 }
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700498 return ReportCopyFailure(from, to, msg);
499 }
500
501 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6d929972015-10-27 13:40:35 -0700502 std::vector<char> buf(msg.status.msglen + 1);
503 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700504 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
505 from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700506 return false;
507 }
Elliott Hughes6d929972015-10-27 13:40:35 -0700508 buf[msg.status.msglen] = 0;
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800509 Error("failed to copy '%s' to '%s': remote %s", from, to, &buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700510 return false;
511 }
512
Elliott Hughesb708d162015-10-27 16:03:15 -0700513
Josh Gao983c41c2015-11-02 17:15:57 -0800514 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
515 std::string s;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800516
Josh Gao983c41c2015-11-02 17:15:57 -0800517 va_list ap;
518 va_start(ap, fmt);
519 android::base::StringAppendV(&s, fmt, ap);
520 va_end(ap);
521
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800522 line_printer_.Print(s, LinePrinter::INFO);
Josh Gao983c41c2015-11-02 17:15:57 -0800523 }
524
Josh Gao1a9979e2016-08-04 11:43:00 -0700525 void Println(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
526 std::string s;
527
528 va_list ap;
529 va_start(ap, fmt);
530 android::base::StringAppendV(&s, fmt, ap);
531 va_end(ap);
532
533 line_printer_.Print(s, LinePrinter::INFO);
534 line_printer_.KeepInfoLine();
535 }
536
Elliott Hughesb708d162015-10-27 16:03:15 -0700537 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
538 std::string s = "adb: error: ";
539
540 va_list ap;
541 va_start(ap, fmt);
542 android::base::StringAppendV(&s, fmt, ap);
543 va_end(ap);
544
Elliott Hughes77f539a2015-12-08 16:01:15 -0800545 line_printer_.Print(s, LinePrinter::ERROR);
Elliott Hughesb708d162015-10-27 16:03:15 -0700546 }
547
Josh Gao21abf5a2015-11-07 17:18:44 -0800548 void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
549 std::string s = "adb: warning: ";
550
551 va_list ap;
552 va_start(ap, fmt);
553 android::base::StringAppendV(&s, fmt, ap);
554 va_end(ap);
555
Elliott Hughes77f539a2015-12-08 16:01:15 -0800556 line_printer_.Print(s, LinePrinter::WARNING);
Josh Gao21abf5a2015-11-07 17:18:44 -0800557 }
558
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800559 void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700560 current_ledger_.bytes_expected = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800561 for (const copyinfo& ci : file_list) {
562 // Unfortunately, this doesn't work for symbolic links, because we'll copy the
563 // target of the link rather than just creating a link. (But ci.size is the link size.)
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700564 if (!ci.skip) current_ledger_.bytes_expected += ci.size;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800565 }
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700566 current_ledger_.expect_multiple_files = true;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800567 }
568
569 void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700570 current_ledger_.bytes_expected = expected_total_bytes;
571 current_ledger_.expect_multiple_files = false;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800572 }
573
Elliott Hughesaa245492015-08-03 10:38:08 -0700574 // TODO: add a char[max] buffer here, to replace syncsendbuf...
575 int fd;
576 size_t max;
577
578 private:
Josh Gaoda811952016-02-19 15:55:55 -0800579 bool expect_done_;
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800580 bool have_stat_v2_;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800581
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700582 TransferLedger global_ledger_;
583 TransferLedger current_ledger_;
Elliott Hughesb708d162015-10-27 16:03:15 -0700584 LinePrinter line_printer_;
Elliott Hughesaa245492015-08-03 10:38:08 -0700585
Spencer Low351ecd12015-10-14 17:32:44 -0700586 bool SendQuit() {
587 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesaa245492015-08-03 10:38:08 -0700588 }
589
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800590 bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
591 if (!WriteFdExactly(fd, data, data_length)) {
592 if (errno == ECONNRESET) {
593 // Assume adbd told us why it was closing the connection, and
594 // try to read failure reason from adbd.
595 syncmsg msg;
596 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
597 Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
598 } else if (msg.status.id != ID_FAIL) {
599 Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
600 } else {
601 ReportCopyFailure(from, to, msg);
602 }
603 } else {
604 Error("%zu-byte write failed: %s", data_length, strerror(errno));
605 }
606 _exit(1);
607 }
608 return true;
609 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700610};
611
Josh Gaocda6a2b2015-11-02 16:45:47 -0800612typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesaa245492015-08-03 10:38:08 -0700613
Josh Gaocda6a2b2015-11-02 16:45:47 -0800614static bool sync_ls(SyncConnection& sc, const char* path,
Chih-Hung Hsieh8f7b9e32016-07-27 16:25:51 -0700615 const std::function<sync_ls_cb>& func) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700616 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700617
618 while (true) {
619 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700620 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700621
622 if (msg.dent.id == ID_DONE) return true;
623 if (msg.dent.id != ID_DENT) return false;
624
Elliott Hughesf4465202015-08-24 14:27:03 -0700625 size_t len = msg.dent.namelen;
Elliott Hughesaa245492015-08-03 10:38:08 -0700626 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800627
Elliott Hughes5c742702015-07-30 17:42:01 -0700628 char buf[257];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700629 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800630 buf[len] = 0;
631
Josh Gaocda6a2b2015-11-02 16:45:47 -0800632 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800633 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800634}
635
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800636static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
637 return sc.SendStat(path) && sc.FinishStat(st);
638}
639
640static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) {
641 return sc.SendLstat(path) && sc.FinishStat(st);
642}
643
644static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) {
645 if (sync_stat(sc, path, st)) {
646 return true;
647 }
648
649 if (errno != ENOTSUP) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700650 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800651 }
652
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800653 // Try to emulate the parts we can when talking to older adbds.
654 bool lstat_result = sync_lstat(sc, path, st);
655 if (!lstat_result) {
656 return false;
657 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800658
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800659 if (S_ISLNK(st->st_mode)) {
660 // If the target is a symlink, figure out whether it's a file or a directory.
661 // Also, zero out the st_size field, since no one actually cares what the path length is.
662 st->st_size = 0;
663 std::string dir_path = path;
664 dir_path.push_back('/');
665 struct stat tmp_st;
666
667 st->st_mode &= ~S_IFMT;
668 if (sync_lstat(sc, dir_path.c_str(), &tmp_st)) {
669 st->st_mode |= S_IFDIR;
670 } else {
671 st->st_mode |= S_IFREG;
672 }
673 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700674 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800675}
676
Dan Albert06b0d6b2017-05-18 22:56:48 -0700677static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime,
678 mode_t mode, bool sync) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700679 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
680
Dan Albert06b0d6b2017-05-18 22:56:48 -0700681 if (sync) {
682 struct stat st;
683 if (sync_lstat(sc, rpath, &st)) {
684 // For links, we cannot update the atime/mtime.
685 if ((S_ISREG(mode & st.st_mode) && st.st_mtime == static_cast<time_t>(mtime)) ||
686 (S_ISLNK(mode & st.st_mode) && st.st_mtime >= static_cast<time_t>(mtime))) {
687 sc.RecordFilesSkipped(1);
688 return true;
689 }
690 }
691 }
692
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700693 if (S_ISLNK(mode)) {
694#if !defined(_WIN32)
695 char buf[PATH_MAX];
696 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
697 if (data_length == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700698 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700699 return false;
700 }
701 buf[data_length++] = '\0';
702
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800703 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
704 return false;
705 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700706 return sc.CopyDone(lpath, rpath);
707#endif
708 }
709
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700710 struct stat st;
711 if (stat(lpath, &st) == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700712 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700713 return false;
714 }
715 if (st.st_size < SYNC_DATA_MAX) {
716 std::string data;
Josh Gao94dc19f2016-09-14 16:13:50 -0700717 if (!android::base::ReadFileToString(lpath, &data, true)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700718 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700719 return false;
720 }
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800721 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
722 data.data(), data.size())) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700723 return false;
724 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700725 } else {
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800726 if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700727 return false;
728 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700729 }
730 return sc.CopyDone(lpath, rpath);
731}
732
Felipe Leme44a42672016-04-01 17:43:27 -0700733static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
Josh Gaoaac11452016-12-06 14:07:53 -0800734 const char* name, uint64_t expected_size) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700735 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800736
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700737 adb_unlink(lpath);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700738 int lfd = adb_creat(lpath, 0644);
739 if (lfd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700740 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700741 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800742 }
743
Elliott Hughesb708d162015-10-27 16:03:15 -0700744 uint64_t bytes_copied = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700745 while (true) {
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700746 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700747 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700748 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700749 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700750 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800751 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800752
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700753 if (msg.data.id == ID_DONE) break;
754
755 if (msg.data.id != ID_DATA) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800756 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700757 adb_unlink(lpath);
758 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700759 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800760 }
761
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700762 if (msg.data.size > sc.max) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700763 sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800764 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700765 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700766 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800767 }
768
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700769 char buffer[SYNC_DATA_MAX];
770 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800771 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700772 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700773 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800774 }
775
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700776 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700777 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700778 adb_close(lfd);
779 adb_unlink(lpath);
780 return false;
781 }
782
Elliott Hughesb708d162015-10-27 16:03:15 -0700783 bytes_copied += msg.data.size;
784
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700785 sc.RecordBytesTransferred(msg.data.size);
Josh Gaoaac11452016-12-06 14:07:53 -0800786 sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800787 }
788
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700789 sc.RecordFilesTransferred(1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800790 adb_close(lfd);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700791 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800792}
793
Elliott Hughesaa245492015-08-03 10:38:08 -0700794bool do_sync_ls(const char* path) {
795 SyncConnection sc;
796 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800797
Josh Gaocda6a2b2015-11-02 16:45:47 -0800798 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
799 const char* name) {
800 printf("%08x %08x %08x %s\n", mode, size, time, name);
801 });
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800802}
803
Elliott Hughesaa245492015-08-03 10:38:08 -0700804static bool IsDotOrDotDot(const char* name) {
805 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
806}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800807
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800808static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800809 const std::string& lpath,
810 const std::string& rpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800811 std::vector<copyinfo> dirlist;
Josh Gaod9731572015-11-03 15:23:03 -0800812 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
Elliott Hughesaa245492015-08-03 10:38:08 -0700813 if (!dir) {
Josh Gaod9731572015-11-03 15:23:03 -0800814 sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800815 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800816 }
817
Josh Gao65800962015-11-04 14:57:04 -0800818 bool empty_dir = true;
Elliott Hughesb708d162015-10-27 16:03:15 -0700819 dirent* de;
Elliott Hughesaa245492015-08-03 10:38:08 -0700820 while ((de = readdir(dir.get()))) {
Josh Gao65800962015-11-04 14:57:04 -0800821 if (IsDotOrDotDot(de->d_name)) {
822 continue;
823 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700824
Josh Gao65800962015-11-04 14:57:04 -0800825 empty_dir = false;
Josh Gaod9731572015-11-03 15:23:03 -0800826 std::string stat_path = lpath + de->d_name;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800827
Elliott Hughesaa245492015-08-03 10:38:08 -0700828 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800829 if (lstat(stat_path.c_str(), &st) == -1) {
Josh Gaod9731572015-11-03 15:23:03 -0800830 sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
831 strerror(errno));
Josh Gao12a2ae92015-11-07 15:27:26 -0800832 continue;
833 }
834
Josh Gaof2642242015-12-09 14:03:30 -0800835 copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
Josh Gao12a2ae92015-11-07 15:27:26 -0800836 if (S_ISDIR(st.st_mode)) {
837 dirlist.push_back(ci);
838 } else {
Josh Gao48bc0d72016-03-02 16:11:13 -0800839 if (!should_push_file(st.st_mode)) {
840 sc.Warning("skipping special file '%s' (mode = 0o%o)", lpath.c_str(), st.st_mode);
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800841 ci.skip = true;
Josh Gao12a2ae92015-11-07 15:27:26 -0800842 }
Josh Gao48bc0d72016-03-02 16:11:13 -0800843 ci.time = st.st_mtime;
844 ci.size = st.st_size;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800845 file_list->push_back(ci);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800846 }
847 }
848
Elliott Hughesaa245492015-08-03 10:38:08 -0700849 // Close this directory and recurse.
850 dir.reset();
Josh Gao65800962015-11-04 14:57:04 -0800851
852 // Add the current directory to the list if it was empty, to ensure that
853 // it gets created.
854 if (empty_dir) {
855 // TODO(b/25566053): Make pushing empty directories work.
856 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao21abf5a2015-11-07 17:18:44 -0800857 sc.Warning("skipping empty directory '%s'", lpath.c_str());
Colin Cross58021d12017-02-23 21:23:05 -0800858 copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
859 android::base::Basename(lpath), S_IFDIR);
Josh Gao65800962015-11-04 14:57:04 -0800860 ci.skip = true;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800861 file_list->push_back(ci);
Josh Gao65800962015-11-04 14:57:04 -0800862 return true;
863 }
864
Josh Gaocda6a2b2015-11-02 16:45:47 -0800865 for (const copyinfo& ci : dirlist) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800866 local_build_list(sc, file_list, ci.lpath, ci.rpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800867 }
868
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800869 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800870}
871
Josh Gaod9731572015-11-03 15:23:03 -0800872static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
873 std::string rpath, bool check_timestamps,
874 bool list_only) {
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700875 sc.NewTransfer();
876
Josh Gaod9731572015-11-03 15:23:03 -0800877 // Make sure that both directory paths end in a slash.
Josh Gao1a025302015-11-09 11:12:14 -0800878 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800879 ensure_trailing_separators(lpath, rpath);
Josh Gaod9731572015-11-03 15:23:03 -0800880
881 // Recursively build the list of files to copy.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800882 std::vector<copyinfo> file_list;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800883 int skipped = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800884 if (!local_build_list(sc, &file_list, lpath, rpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700885 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800886 }
887
Elliott Hughesaa245492015-08-03 10:38:08 -0700888 if (check_timestamps) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800889 for (const copyinfo& ci : file_list) {
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800890 if (!sc.SendLstat(ci.rpath.c_str())) {
891 sc.Error("failed to send lstat");
Josh Gaod9731572015-11-03 15:23:03 -0800892 return false;
893 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800894 }
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800895 for (copyinfo& ci : file_list) {
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800896 struct stat st;
897 if (sc.FinishStat(&st)) {
898 if (st.st_size == static_cast<off_t>(ci.size)) {
899 // For links, we cannot update the atime/mtime.
900 if ((S_ISREG(ci.mode & st.st_mode) && st.st_mtime == ci.time) ||
901 (S_ISLNK(ci.mode & st.st_mode) && st.st_mtime >= ci.time)) {
902 ci.skip = true;
903 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700904 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800905 }
906 }
907 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800908
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800909 sc.ComputeExpectedTotalBytes(file_list);
910
911 for (const copyinfo& ci : file_list) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800912 if (!ci.skip) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700913 if (list_only) {
Josh Gaobaa215e2016-08-04 14:55:23 -0700914 sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
Elliott Hughesb708d162015-10-27 16:03:15 -0700915 } else {
Dan Albert06b0d6b2017-05-18 22:56:48 -0700916 if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode, false)) {
Josh Gaod9731572015-11-03 15:23:03 -0800917 return false;
Elliott Hughesb708d162015-10-27 16:03:15 -0700918 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800919 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800920 } else {
921 skipped++;
922 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800923 }
924
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700925 sc.RecordFilesSkipped(skipped);
926 sc.ReportTransferRate(lpath, TransferDirection::push);
Elliott Hughesaa245492015-08-03 10:38:08 -0700927 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800928}
929
Dan Albert06b0d6b2017-05-18 22:56:48 -0700930bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700931 SyncConnection sc;
932 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800933
Josh Gao05786772015-10-30 16:57:19 -0700934 bool success = true;
Josh Gao5a1e3fd2016-12-05 17:11:34 -0800935 bool dst_exists;
936 bool dst_isdir;
937
938 struct stat st;
939 if (sync_stat_fallback(sc, dst, &st)) {
940 dst_exists = true;
941 dst_isdir = S_ISDIR(st.st_mode);
942 } else {
943 if (errno == ENOENT || errno == ENOPROTOOPT) {
944 dst_exists = false;
945 dst_isdir = false;
946 } else {
947 sc.Error("stat failed when trying to push to %s: %s", dst, strerror(errno));
948 return false;
949 }
950 }
Josh Gao05786772015-10-30 16:57:19 -0700951
Josh Gao07db1192015-11-07 15:38:19 -0800952 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700953 if (srcs.size() > 1) {
954 sc.Error("target '%s' is not a directory", dst);
955 return false;
956 } else {
957 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -0800958
959 // A path that ends with a slash doesn't have to be a directory if
960 // it doesn't exist yet.
961 if (dst[dst_len - 1] == '/' && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -0700962 sc.Error("failed to access '%s': Not a directory", dst);
963 return false;
964 }
965 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700966 }
Josh Gao05786772015-10-30 16:57:19 -0700967
968 for (const char* src_path : srcs) {
969 const char* dst_path = dst;
970 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800971 if (stat(src_path, &st) == -1) {
Josh Gao05786772015-10-30 16:57:19 -0700972 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
973 success = false;
974 continue;
975 }
976
977 if (S_ISDIR(st.st_mode)) {
Josh Gao07db1192015-11-07 15:38:19 -0800978 std::string dst_dir = dst;
979
980 // If the destination path existed originally, the source directory
981 // should be copied as a child of the destination.
982 if (dst_exists) {
983 if (!dst_isdir) {
984 sc.Error("target '%s' is not a directory", dst);
985 return false;
986 }
987 // dst is a POSIX path, so we don't want to use the sysdeps
988 // helpers here.
989 if (dst_dir.back() != '/') {
990 dst_dir.push_back('/');
991 }
Colin Cross58021d12017-02-23 21:23:05 -0800992 dst_dir.append(android::base::Basename(src_path));
Josh Gao07db1192015-11-07 15:38:19 -0800993 }
994
Dan Albert06b0d6b2017-05-18 22:56:48 -0700995 success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), sync, false);
Josh Gao05786772015-10-30 16:57:19 -0700996 continue;
Josh Gao48bc0d72016-03-02 16:11:13 -0800997 } else if (!should_push_file(st.st_mode)) {
998 sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
999 continue;
Josh Gao05786772015-10-30 16:57:19 -07001000 }
1001
1002 std::string path_holder;
Josh Gao07db1192015-11-07 15:38:19 -08001003 if (dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -07001004 // If we're copying a local file to a remote directory,
1005 // we really want to copy to remote_dir + "/" + local_filename.
Josh Gao323899b2016-02-03 14:55:24 -08001006 path_holder = dst_path;
1007 if (path_holder.back() != '/') {
1008 path_holder.push_back('/');
1009 }
Colin Cross58021d12017-02-23 21:23:05 -08001010 path_holder += android::base::Basename(src_path);
Josh Gao05786772015-10-30 16:57:19 -07001011 dst_path = path_holder.c_str();
1012 }
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001013
1014 sc.NewTransfer();
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001015 sc.SetExpectedTotalBytes(st.st_size);
Dan Albert06b0d6b2017-05-18 22:56:48 -07001016 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync);
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001017 sc.ReportTransferRate(src_path, TransferDirection::push);
Josh Gao05786772015-10-30 16:57:19 -07001018 }
1019
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001020 sc.ReportOverallTransferRate(TransferDirection::push);
Josh Gao05786772015-10-30 16:57:19 -07001021 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001022}
1023
Josh Gaoa63b17f2016-02-25 17:12:45 -08001024static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
1025 const std::string& rpath, const std::string& lpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -08001026 std::vector<copyinfo> dirlist;
Josh Gaof2642242015-12-09 14:03:30 -08001027 std::vector<copyinfo> linklist;
Josh Gaoa63b17f2016-02-25 17:12:45 -08001028
1029 // Add an entry for the current directory to ensure it gets created before pulling its contents.
Colin Cross58021d12017-02-23 21:23:05 -08001030 copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
1031 android::base::Basename(lpath), S_IFDIR);
Josh Gaoa63b17f2016-02-25 17:12:45 -08001032 file_list->push_back(ci);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001033
Elliott Hughesaa245492015-08-03 10:38:08 -07001034 // Put the files/dirs in rpath on the lists.
Josh Gaodd6cc4d2015-11-30 10:21:25 -08001035 auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
Josh Gao65800962015-11-04 14:57:04 -08001036 if (IsDotOrDotDot(name)) {
1037 return;
1038 }
Josh Gaocda6a2b2015-11-02 16:45:47 -08001039
Josh Gaof2642242015-12-09 14:03:30 -08001040 copyinfo ci(lpath, rpath, name, mode);
Josh Gao65800962015-11-04 14:57:04 -08001041 if (S_ISDIR(mode)) {
1042 dirlist.push_back(ci);
Josh Gaof2642242015-12-09 14:03:30 -08001043 } else if (S_ISLNK(mode)) {
1044 linklist.push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -08001045 } else {
Josh Gao48bc0d72016-03-02 16:11:13 -08001046 if (!should_pull_file(ci.mode)) {
1047 sc.Warning("skipping special file '%s' (mode = 0o%o)", ci.rpath.c_str(), ci.mode);
1048 ci.skip = true;
1049 }
Josh Gaof2642242015-12-09 14:03:30 -08001050 ci.time = time;
1051 ci.size = size;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001052 file_list->push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -08001053 }
1054 };
1055
Josh Gaod9731572015-11-03 15:23:03 -08001056 if (!sync_ls(sc, rpath.c_str(), callback)) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001057 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001058 }
1059
Josh Gaof2642242015-12-09 14:03:30 -08001060 // Check each symlink we found to see whether it's a file or directory.
1061 for (copyinfo& link_ci : linklist) {
Josh Gao5a1e3fd2016-12-05 17:11:34 -08001062 struct stat st;
1063 if (!sync_stat_fallback(sc, link_ci.rpath.c_str(), &st)) {
1064 sc.Warning("stat failed for path %s: %s", link_ci.rpath.c_str(), strerror(errno));
1065 continue;
1066 }
1067
1068 if (S_ISDIR(st.st_mode)) {
Josh Gaof2642242015-12-09 14:03:30 -08001069 dirlist.emplace_back(std::move(link_ci));
1070 } else {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001071 file_list->emplace_back(std::move(link_ci));
Josh Gaof2642242015-12-09 14:03:30 -08001072 }
1073 }
1074
Elliott Hughesaa245492015-08-03 10:38:08 -07001075 // Recurse into each directory we found.
Josh Gaocda6a2b2015-11-02 16:45:47 -08001076 while (!dirlist.empty()) {
1077 copyinfo current = dirlist.back();
1078 dirlist.pop_back();
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001079 if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001080 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001081 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001082 }
1083
Elliott Hughesaa245492015-08-03 10:38:08 -07001084 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001085}
1086
Josh Gao1a025302015-11-09 11:12:14 -08001087static int set_time_and_mode(const std::string& lpath, time_t time,
1088 unsigned int mode) {
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -07001089 struct utimbuf times = { time, time };
Josh Gao1a025302015-11-09 11:12:14 -08001090 int r1 = utime(lpath.c_str(), &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001091
1092 /* use umask for permissions */
Josh Gaocda6a2b2015-11-02 16:45:47 -08001093 mode_t mask = umask(0000);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001094 umask(mask);
Josh Gao1a025302015-11-09 11:12:14 -08001095 int r2 = chmod(lpath.c_str(), mode & ~mask);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001096
Spencer Low363af562015-11-07 18:51:54 -08001097 return r1 ? r1 : r2;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001098}
1099
Josh Gaod9731572015-11-03 15:23:03 -08001100static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
1101 std::string lpath, bool copy_attrs) {
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001102 sc.NewTransfer();
1103
Elliott Hughesaa245492015-08-03 10:38:08 -07001104 // Make sure that both directory paths end in a slash.
Josh Gao12a2ae92015-11-07 15:27:26 -08001105 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001106 ensure_trailing_separators(lpath, rpath);
Riley Andrews4d04d242014-12-12 13:12:36 -08001107
Elliott Hughesaa245492015-08-03 10:38:08 -07001108 // Recursively build the list of files to copy.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001109 sc.Printf("pull: building file list...");
1110 std::vector<copyinfo> file_list;
1111 if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
Josh Gaocda6a2b2015-11-02 16:45:47 -08001112 return false;
1113 }
Elliott Hughesaa245492015-08-03 10:38:08 -07001114
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001115 sc.ComputeExpectedTotalBytes(file_list);
1116
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001117 int skipped = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001118 for (const copyinfo &ci : file_list) {
Josh Gaofc7c3b62015-11-03 14:44:04 -08001119 if (!ci.skip) {
Josh Gao65800962015-11-04 14:57:04 -08001120 if (S_ISDIR(ci.mode)) {
1121 // Entry is for an empty directory, create it and continue.
1122 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao1a025302015-11-09 11:12:14 -08001123 if (!mkdirs(ci.lpath)) {
Josh Gao65800962015-11-04 14:57:04 -08001124 sc.Error("failed to create directory '%s': %s",
Josh Gao1a025302015-11-09 11:12:14 -08001125 ci.lpath.c_str(), strerror(errno));
Josh Gao65800962015-11-04 14:57:04 -08001126 return false;
1127 }
Josh Gao65800962015-11-04 14:57:04 -08001128 continue;
1129 }
1130
Josh Gaoaac11452016-12-06 14:07:53 -08001131 if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str(), nullptr, ci.size)) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001132 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001133 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001134
Josh Gao1a025302015-11-09 11:12:14 -08001135 if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001136 return false;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001137 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001138 } else {
1139 skipped++;
1140 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001141 }
1142
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001143 sc.RecordFilesSkipped(skipped);
1144 sc.ReportTransferRate(rpath, TransferDirection::pull);
Elliott Hughesaa245492015-08-03 10:38:08 -07001145 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001146}
1147
Josh Gao05786772015-10-30 16:57:19 -07001148bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
Felipe Leme44a42672016-04-01 17:43:27 -07001149 bool copy_attrs, const char* name) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001150 SyncConnection sc;
1151 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001152
Josh Gao05786772015-10-30 16:57:19 -07001153 bool success = true;
Josh Gao05786772015-10-30 16:57:19 -07001154 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -08001155 bool dst_exists = true;
1156
1157 if (stat(dst, &st) == -1) {
1158 dst_exists = false;
1159
1160 // If we're only pulling one path, the destination path might point to
Josh Gao05786772015-10-30 16:57:19 -07001161 // a path that doesn't exist yet.
Josh Gao12a2ae92015-11-07 15:27:26 -08001162 if (srcs.size() == 1 && errno == ENOENT) {
1163 // However, its parent must exist.
1164 struct stat parent_st;
Colin Cross58021d12017-02-23 21:23:05 -08001165 if (stat(android::base::Dirname(dst).c_str(), &parent_st) == -1) {
Josh Gao12a2ae92015-11-07 15:27:26 -08001166 sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
1167 return false;
1168 }
1169 } else {
1170 sc.Error("failed to access '%s': %s", dst, strerror(errno));
Josh Gao05786772015-10-30 16:57:19 -07001171 return false;
1172 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001173 }
1174
Josh Gao07db1192015-11-07 15:38:19 -08001175 bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
1176 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -07001177 if (srcs.size() > 1) {
1178 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -07001179 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001180 } else {
Josh Gao05786772015-10-30 16:57:19 -07001181 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -08001182
1183 // A path that ends with a slash doesn't have to be a directory if
1184 // it doesn't exist yet.
Josh Gao1a025302015-11-09 11:12:14 -08001185 if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -07001186 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -07001187 return false;
Elliott Hughes5c742702015-07-30 17:42:01 -07001188 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001189 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001190 }
Elliott Hughesaa245492015-08-03 10:38:08 -07001191
Josh Gao05786772015-10-30 16:57:19 -07001192 for (const char* src_path : srcs) {
1193 const char* dst_path = dst;
Josh Gao5a1e3fd2016-12-05 17:11:34 -08001194 struct stat src_st;
1195 if (!sync_stat_fallback(sc, src_path, &src_st)) {
1196 if (errno == ENOPROTOOPT) {
1197 sc.Error("remote object '%s' does not exist", src_path);
1198 } else {
1199 sc.Error("failed to stat remote object '%s': %s", src_path, strerror(errno));
1200 }
1201
Josh Gao05786772015-10-30 16:57:19 -07001202 success = false;
1203 continue;
1204 }
1205
Josh Gao5a1e3fd2016-12-05 17:11:34 -08001206 bool src_isdir = S_ISDIR(src_st.st_mode);
Josh Gaof2642242015-12-09 14:03:30 -08001207 if (src_isdir) {
Josh Gao07db1192015-11-07 15:38:19 -08001208 std::string dst_dir = dst;
1209
1210 // If the destination path existed originally, the source directory
1211 // should be copied as a child of the destination.
1212 if (dst_exists) {
1213 if (!dst_isdir) {
1214 sc.Error("target '%s' is not a directory", dst);
1215 return false;
1216 }
1217 if (!adb_is_separator(dst_dir.back())) {
1218 dst_dir.push_back(OS_PATH_SEPARATOR);
1219 }
Colin Cross58021d12017-02-23 21:23:05 -08001220 dst_dir.append(android::base::Basename(src_path));
Josh Gao07db1192015-11-07 15:38:19 -08001221 }
1222
Josh Gaof2642242015-12-09 14:03:30 -08001223 success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
Josh Gao05786772015-10-30 16:57:19 -07001224 continue;
Josh Gao5a1e3fd2016-12-05 17:11:34 -08001225 } else if (!should_pull_file(src_st.st_mode)) {
1226 sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode);
Josh Gao48bc0d72016-03-02 16:11:13 -08001227 continue;
1228 }
Josh Gaof2642242015-12-09 14:03:30 -08001229
Josh Gao48bc0d72016-03-02 16:11:13 -08001230 std::string path_holder;
1231 if (dst_isdir) {
1232 // If we're copying a remote file to a local directory, we
1233 // really want to copy to local_dir + OS_PATH_SEPARATOR +
1234 // basename(remote).
1235 path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
Colin Cross58021d12017-02-23 21:23:05 -08001236 android::base::Basename(src_path).c_str());
Josh Gao48bc0d72016-03-02 16:11:13 -08001237 dst_path = path_holder.c_str();
1238 }
Josh Gaof2642242015-12-09 14:03:30 -08001239
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001240 sc.NewTransfer();
Josh Gao5a1e3fd2016-12-05 17:11:34 -08001241 sc.SetExpectedTotalBytes(src_st.st_size);
Josh Gaoaac11452016-12-06 14:07:53 -08001242 if (!sync_recv(sc, src_path, dst_path, name, src_st.st_size)) {
Josh Gao48bc0d72016-03-02 16:11:13 -08001243 success = false;
1244 continue;
1245 }
1246
Josh Gao5a1e3fd2016-12-05 17:11:34 -08001247 if (copy_attrs && set_time_and_mode(dst_path, src_st.st_mtime, src_st.st_mode) != 0) {
Josh Gao48bc0d72016-03-02 16:11:13 -08001248 success = false;
1249 continue;
Josh Gao05786772015-10-30 16:57:19 -07001250 }
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001251 sc.ReportTransferRate(src_path, TransferDirection::pull);
Josh Gao05786772015-10-30 16:57:19 -07001252 }
1253
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001254 sc.ReportOverallTransferRate(TransferDirection::pull);
Josh Gao05786772015-10-30 16:57:19 -07001255 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001256}
1257
Elliott Hughesaa245492015-08-03 10:38:08 -07001258bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001259 SyncConnection sc;
1260 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001261
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001262 bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only);
1263 if (!list_only) {
1264 sc.ReportOverallTransferRate(TransferDirection::push);
1265 }
1266 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001267}