blob: f1e4179c3271c2108adea56eb7b6531be67c547b [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>
18#include <errno.h>
Spencer Low6001c872015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albert76649012015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albert76649012015-02-24 15:51:19 -080027#include <time.h>
Elliott Hughesae5a6c02015-09-27 12:55:37 -070028#include <unistd.h>
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -070029#include <utime.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080030
Josh Gaofb0c5cb2016-08-04 14:53:17 -070031#include <chrono>
Josh Gaocda6a2b2015-11-02 16:45:47 -080032#include <functional>
Elliott Hughesa925dba2015-08-24 14:49:43 -070033#include <memory>
Josh Gaofb0c5cb2016-08-04 14:53:17 -070034#include <sstream>
35#include <string>
Elliott Hughes6d929972015-10-27 13:40:35 -070036#include <vector>
Elliott Hughesa925dba2015-08-24 14:49:43 -070037
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080038#include "sysdeps.h"
Dan Albert76649012015-02-24 15:51:19 -080039
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080040#include "adb.h"
41#include "adb_client.h"
Dan Albertcc731cc2015-02-24 21:26:58 -080042#include "adb_io.h"
Alex Vallée14216142015-05-06 17:22:25 -040043#include "adb_utils.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080044#include "file_sync_service.h"
Elliott Hughesb708d162015-10-27 16:03:15 -070045#include "line_printer.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) {
67 return mode & (S_IFREG | S_IFBLK | S_IFCHR);
68}
69
70static bool should_push_file(mode_t mode) {
71 mode_t mask = S_IFREG;
72#if !defined(_WIN32)
73 mask |= S_IFLNK;
74#endif
75 return mode & mask;
76}
77
Elliott Hughesa00e6ef2015-12-17 17:05:29 -080078struct copyinfo {
79 std::string lpath;
80 std::string rpath;
81 unsigned int time = 0;
82 unsigned int mode;
83 uint64_t size = 0;
84 bool skip = false;
85
86 copyinfo(const std::string& local_path,
87 const std::string& remote_path,
88 const std::string& name,
89 unsigned int mode)
90 : lpath(local_path), rpath(remote_path), mode(mode) {
91 ensure_trailing_separators(lpath, rpath);
92 lpath.append(name);
93 rpath.append(name);
94 if (S_ISDIR(mode)) {
95 ensure_trailing_separators(lpath, rpath);
96 }
97 }
98};
99
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700100enum class TransferDirection {
101 push,
102 pull,
103};
104
105struct TransferLedger {
106 std::chrono::steady_clock::time_point start_time;
107 uint64_t files_transferred;
108 uint64_t files_skipped;
109 uint64_t bytes_transferred;
110 uint64_t bytes_expected;
111 bool expect_multiple_files;
112
113 TransferLedger() {
114 Reset();
115 }
116
117 bool operator==(const TransferLedger& other) const {
118 return files_transferred == other.files_transferred &&
119 files_skipped == other.files_skipped && bytes_transferred == other.bytes_transferred;
120 }
121
122 bool operator!=(const TransferLedger& other) const {
123 return !(*this == other);
124 }
125
126 void Reset() {
127 start_time = std::chrono::steady_clock::now();
128 files_transferred = 0;
129 files_skipped = 0;
130 bytes_transferred = 0;
131 bytes_expected = 0;
132 }
133
134 std::string TransferRate() {
135 if (bytes_transferred == 0) return "";
136
137 std::chrono::duration<double> duration;
138 duration = std::chrono::steady_clock::now() - start_time;
139
140 double s = duration.count();
141 if (s == 0) {
142 return "";
143 }
144 double rate = (static_cast<double>(bytes_transferred) / s) / (1024 * 1024);
145 return android::base::StringPrintf(" %.1f MB/s (%" PRIu64 " bytes in %.3fs)", rate,
146 bytes_transferred, s);
147 }
148
149 void ReportProgress(LinePrinter& lp, const std::string& file, uint64_t file_copied_bytes,
150 uint64_t file_total_bytes) {
151 char overall_percentage_str[5] = "?";
152 if (bytes_expected != 0) {
153 int overall_percentage = static_cast<int>(bytes_transferred * 100 / bytes_expected);
154 // If we're pulling symbolic links, we'll pull the target of the link rather than
155 // just create a local link, and that will cause us to go over 100%.
156 if (overall_percentage <= 100) {
157 snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
158 overall_percentage);
159 }
160 }
161
162 std::string output;
163 if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
164 // This case can happen if we're racing against something that wrote to the file
165 // between our stat and our read, or if we're reading a magic file that lies about
166 // its size. Just show how much we've copied.
167 output = android::base::StringPrintf("[%4s] %s: %" PRId64 "/?", overall_percentage_str,
168 file.c_str(), file_copied_bytes);
169 } else {
170 // If we're transferring multiple files, we want to know how far through the current
171 // file we are, as well as the overall percentage.
172 if (expect_multiple_files) {
173 int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
174 output = android::base::StringPrintf("[%4s] %s: %d%%", overall_percentage_str,
175 file.c_str(), file_percentage);
176 } else {
177 output =
178 android::base::StringPrintf("[%4s] %s", overall_percentage_str, file.c_str());
179 }
180 }
181 lp.Print(output, LinePrinter::LineType::INFO);
182 }
183
184 void ReportTransferRate(LinePrinter& lp, const std::string& name, TransferDirection direction) {
185 const char* direction_str = (direction == TransferDirection::push) ? "pushed" : "pulled";
186 std::stringstream ss;
187 if (!name.empty()) {
188 ss << name << ": ";
189 }
190 ss << files_transferred << " file" << ((files_transferred == 1) ? "" : "s") << " "
191 << direction_str << ".";
192 if (files_skipped > 0) {
193 ss << " " << files_skipped << " file" << ((files_skipped == 1) ? "" : "s")
194 << " skipped.";
195 }
196 ss << TransferRate();
197
198 lp.Print(ss.str(), LinePrinter::LineType::INFO);
199 lp.KeepInfoLine();
200 }
201};
202
Elliott Hughesaa245492015-08-03 10:38:08 -0700203class SyncConnection {
204 public:
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700205 SyncConnection() : expect_done_(false) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700206 max = SYNC_DATA_MAX; // TODO: decide at runtime.
207
208 std::string error;
209 fd = adb_connect("sync:", &error);
210 if (fd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700211 Error("connect failed: %s", error.c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700212 }
213 }
214
215 ~SyncConnection() {
216 if (!IsValid()) return;
217
Spencer Low351ecd12015-10-14 17:32:44 -0700218 if (SendQuit()) {
219 // We sent a quit command, so the server should be doing orderly
220 // shutdown soon. But if we encountered an error while we were using
221 // the connection, the server might still be sending data (before
222 // doing orderly shutdown), in which case we won't wait for all of
223 // the data nor the coming orderly shutdown. In the common success
224 // case, this will wait for the server to do orderly shutdown.
225 ReadOrderlyShutdown(fd);
226 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700227 adb_close(fd);
Elliott Hughes77f539a2015-12-08 16:01:15 -0800228
229 line_printer_.KeepInfoLine();
Elliott Hughesaa245492015-08-03 10:38:08 -0700230 }
231
232 bool IsValid() { return fd >= 0; }
233
Josh Gaoda811952016-02-19 15:55:55 -0800234 bool ReceivedError(const char* from, const char* to) {
235 adb_pollfd pfd = {.fd = fd, .events = POLLIN};
236 int rc = adb_poll(&pfd, 1, 0);
237 if (rc < 0) {
238 Error("failed to poll: %s", strerror(errno));
239 return true;
240 }
241 return rc != 0;
242 }
243
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700244 void NewTransfer() {
245 current_ledger_.Reset();
246 }
247
248 void RecordBytesTransferred(size_t bytes) {
249 current_ledger_.bytes_transferred += bytes;
250 global_ledger_.bytes_transferred += bytes;
251 }
252
253 void RecordFilesTransferred(size_t files) {
254 current_ledger_.files_transferred += files;
255 global_ledger_.files_transferred += files;
256 }
257
258 void RecordFilesSkipped(size_t files) {
259 current_ledger_.files_skipped += files;
260 global_ledger_.files_skipped += files;
261 }
262
263 void ReportProgress(const std::string& file, uint64_t file_copied_bytes,
264 uint64_t file_total_bytes) {
265 current_ledger_.ReportProgress(line_printer_, file, file_copied_bytes, file_total_bytes);
266 }
267
268 void ReportTransferRate(const std::string& file, TransferDirection direction) {
269 current_ledger_.ReportTransferRate(line_printer_, file, direction);
270 }
271
272 void ReportOverallTransferRate(TransferDirection direction) {
273 if (current_ledger_ != global_ledger_) {
274 global_ledger_.ReportTransferRate(line_printer_, "", direction);
275 }
276 }
277
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700278 bool SendRequest(int id, const char* path_and_mode) {
279 size_t path_length = strlen(path_and_mode);
280 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700281 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700282 errno = ENAMETOOLONG;
283 return false;
284 }
285
286 // Sending header and payload in a single write makes a noticeable
287 // difference to "adb sync" performance.
Elliott Hughes6d929972015-10-27 13:40:35 -0700288 std::vector<char> buf(sizeof(SyncRequest) + path_length);
289 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700290 req->id = id;
291 req->path_length = path_length;
292 char* data = reinterpret_cast<char*>(req + 1);
293 memcpy(data, path_and_mode, path_length);
294
Elliott Hughes6d929972015-10-27 13:40:35 -0700295 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700296 }
297
298 // Sending header, payload, and footer in a single write makes a huge
299 // difference to "adb sync" performance.
300 bool SendSmallFile(const char* path_and_mode,
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800301 const char* lpath, const char* rpath,
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800302 unsigned mtime,
303 const char* data, size_t data_length) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700304 size_t path_length = strlen(path_and_mode);
305 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700306 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700307 errno = ENAMETOOLONG;
308 return false;
309 }
310
Elliott Hughes6d929972015-10-27 13:40:35 -0700311 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800312 sizeof(SyncRequest) + data_length +
313 sizeof(SyncRequest));
Elliott Hughes6d929972015-10-27 13:40:35 -0700314 char* p = &buf[0];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700315
316 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
317 req_send->id = ID_SEND;
318 req_send->path_length = path_length;
319 p += sizeof(SyncRequest);
320 memcpy(p, path_and_mode, path_length);
321 p += path_length;
322
323 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
324 req_data->id = ID_DATA;
325 req_data->path_length = data_length;
326 p += sizeof(SyncRequest);
327 memcpy(p, data, data_length);
328 p += data_length;
329
330 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
331 req_done->id = ID_DONE;
332 req_done->path_length = mtime;
333 p += sizeof(SyncRequest);
334
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800335 WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
Josh Gaoda811952016-02-19 15:55:55 -0800336 expect_done_ = true;
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700337
338 // RecordFilesTransferred gets called in CopyDone.
339 RecordBytesTransferred(data_length);
Josh Gaof22bc602016-03-01 11:46:02 -0800340 ReportProgress(rpath, data_length, data_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700341 return true;
342 }
343
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800344 bool SendLargeFile(const char* path_and_mode,
345 const char* lpath, const char* rpath,
346 unsigned mtime) {
347 if (!SendRequest(ID_SEND, path_and_mode)) {
348 Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
349 return false;
350 }
351
352 struct stat st;
353 if (stat(lpath, &st) == -1) {
354 Error("cannot stat '%s': %s", lpath, strerror(errno));
355 return false;
356 }
357
358 uint64_t total_size = st.st_size;
359 uint64_t bytes_copied = 0;
360
361 int lfd = adb_open(lpath, O_RDONLY);
362 if (lfd < 0) {
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800363 Error("opening '%s' locally failed: %s", lpath, strerror(errno));
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800364 return false;
365 }
366
367 syncsendbuf sbuf;
368 sbuf.id = ID_DATA;
369 while (true) {
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800370 int bytes_read = adb_read(lfd, sbuf.data, max);
371 if (bytes_read == -1) {
372 Error("reading '%s' locally failed: %s", lpath, strerror(errno));
373 adb_close(lfd);
374 return false;
375 } else if (bytes_read == 0) {
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800376 break;
377 }
378
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800379 sbuf.size = bytes_read;
380 WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800381
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700382 RecordBytesTransferred(bytes_read);
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800383 bytes_copied += bytes_read;
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800384
Josh Gaoda811952016-02-19 15:55:55 -0800385 // Check to see if we've received an error from the other side.
386 if (ReceivedError(lpath, rpath)) {
387 break;
388 }
389
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800390 ReportProgress(rpath, bytes_copied, total_size);
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800391 }
392
393 adb_close(lfd);
394
395 syncmsg msg;
396 msg.data.id = ID_DONE;
397 msg.data.size = mtime;
Josh Gaoda811952016-02-19 15:55:55 -0800398 expect_done_ = true;
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700399
400 // RecordFilesTransferred gets called in CopyDone.
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800401 return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800402 }
403
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700404 bool CopyDone(const char* from, const char* to) {
405 syncmsg msg;
406 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Josh Gaoda811952016-02-19 15:55:55 -0800407 Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700408 return false;
409 }
410 if (msg.status.id == ID_OKAY) {
Josh Gaoda811952016-02-19 15:55:55 -0800411 if (expect_done_) {
412 expect_done_ = false;
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700413 RecordFilesTransferred(1);
Josh Gaoda811952016-02-19 15:55:55 -0800414 return true;
415 } else {
416 Error("failed to copy '%s' to '%s': received premature success", from, to);
417 return true;
418 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700419 }
420 if (msg.status.id != ID_FAIL) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700421 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700422 return false;
423 }
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700424 return ReportCopyFailure(from, to, msg);
425 }
426
427 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6d929972015-10-27 13:40:35 -0700428 std::vector<char> buf(msg.status.msglen + 1);
429 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700430 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
431 from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700432 return false;
433 }
Elliott Hughes6d929972015-10-27 13:40:35 -0700434 buf[msg.status.msglen] = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700435 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700436 return false;
437 }
438
Elliott Hughesb708d162015-10-27 16:03:15 -0700439
Josh Gao983c41c2015-11-02 17:15:57 -0800440 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
441 std::string s;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800442
Josh Gao983c41c2015-11-02 17:15:57 -0800443 va_list ap;
444 va_start(ap, fmt);
445 android::base::StringAppendV(&s, fmt, ap);
446 va_end(ap);
447
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800448 line_printer_.Print(s, LinePrinter::INFO);
Josh Gao983c41c2015-11-02 17:15:57 -0800449 }
450
Josh Gao1a9979e2016-08-04 11:43:00 -0700451 void Println(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
452 std::string s;
453
454 va_list ap;
455 va_start(ap, fmt);
456 android::base::StringAppendV(&s, fmt, ap);
457 va_end(ap);
458
459 line_printer_.Print(s, LinePrinter::INFO);
460 line_printer_.KeepInfoLine();
461 }
462
Elliott Hughesb708d162015-10-27 16:03:15 -0700463 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
464 std::string s = "adb: error: ";
465
466 va_list ap;
467 va_start(ap, fmt);
468 android::base::StringAppendV(&s, fmt, ap);
469 va_end(ap);
470
Elliott Hughes77f539a2015-12-08 16:01:15 -0800471 line_printer_.Print(s, LinePrinter::ERROR);
Elliott Hughesb708d162015-10-27 16:03:15 -0700472 }
473
Josh Gao21abf5a2015-11-07 17:18:44 -0800474 void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
475 std::string s = "adb: warning: ";
476
477 va_list ap;
478 va_start(ap, fmt);
479 android::base::StringAppendV(&s, fmt, ap);
480 va_end(ap);
481
Elliott Hughes77f539a2015-12-08 16:01:15 -0800482 line_printer_.Print(s, LinePrinter::WARNING);
Josh Gao21abf5a2015-11-07 17:18:44 -0800483 }
484
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800485 void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700486 current_ledger_.bytes_expected = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800487 for (const copyinfo& ci : file_list) {
488 // Unfortunately, this doesn't work for symbolic links, because we'll copy the
489 // target of the link rather than just creating a link. (But ci.size is the link size.)
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700490 if (!ci.skip) current_ledger_.bytes_expected += ci.size;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800491 }
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700492 current_ledger_.expect_multiple_files = true;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800493 }
494
495 void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700496 current_ledger_.bytes_expected = expected_total_bytes;
497 current_ledger_.expect_multiple_files = false;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800498 }
499
Elliott Hughesaa245492015-08-03 10:38:08 -0700500 // TODO: add a char[max] buffer here, to replace syncsendbuf...
501 int fd;
502 size_t max;
503
504 private:
Josh Gaoda811952016-02-19 15:55:55 -0800505 bool expect_done_;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800506
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700507 TransferLedger global_ledger_;
508 TransferLedger current_ledger_;
Elliott Hughesb708d162015-10-27 16:03:15 -0700509 LinePrinter line_printer_;
Elliott Hughesaa245492015-08-03 10:38:08 -0700510
Spencer Low351ecd12015-10-14 17:32:44 -0700511 bool SendQuit() {
512 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesaa245492015-08-03 10:38:08 -0700513 }
514
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800515 bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
516 if (!WriteFdExactly(fd, data, data_length)) {
517 if (errno == ECONNRESET) {
518 // Assume adbd told us why it was closing the connection, and
519 // try to read failure reason from adbd.
520 syncmsg msg;
521 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
522 Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
523 } else if (msg.status.id != ID_FAIL) {
524 Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
525 } else {
526 ReportCopyFailure(from, to, msg);
527 }
528 } else {
529 Error("%zu-byte write failed: %s", data_length, strerror(errno));
530 }
531 _exit(1);
532 }
533 return true;
534 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700535};
536
Josh Gaocda6a2b2015-11-02 16:45:47 -0800537typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesaa245492015-08-03 10:38:08 -0700538
Josh Gaocda6a2b2015-11-02 16:45:47 -0800539static bool sync_ls(SyncConnection& sc, const char* path,
Chih-Hung Hsieh8f7b9e32016-07-27 16:25:51 -0700540 const std::function<sync_ls_cb>& func) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700541 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700542
543 while (true) {
544 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700545 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700546
547 if (msg.dent.id == ID_DONE) return true;
548 if (msg.dent.id != ID_DENT) return false;
549
Elliott Hughesf4465202015-08-24 14:27:03 -0700550 size_t len = msg.dent.namelen;
Elliott Hughesaa245492015-08-03 10:38:08 -0700551 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800552
Elliott Hughes5c742702015-07-30 17:42:01 -0700553 char buf[257];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700554 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800555 buf[len] = 0;
556
Josh Gaocda6a2b2015-11-02 16:45:47 -0800557 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800558 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800559}
560
Elliott Hughesaa245492015-08-03 10:38:08 -0700561static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
562 unsigned int* mode, unsigned int* size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800563 syncmsg msg;
Elliott Hughesaa245492015-08-03 10:38:08 -0700564 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
565 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800566 }
567
Elliott Hughesf4465202015-08-24 14:27:03 -0700568 if (timestamp) *timestamp = msg.stat.time;
569 if (mode) *mode = msg.stat.mode;
570 if (size) *size = msg.stat.size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800571
Elliott Hughesaa245492015-08-03 10:38:08 -0700572 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800573}
574
Elliott Hughesaa245492015-08-03 10:38:08 -0700575static bool sync_stat(SyncConnection& sc, const char* path,
576 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700577 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800578}
579
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700580static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesb708d162015-10-27 16:03:15 -0700581 unsigned mtime, mode_t mode)
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700582{
583 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
584
585 if (S_ISLNK(mode)) {
586#if !defined(_WIN32)
587 char buf[PATH_MAX];
588 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
589 if (data_length == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700590 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700591 return false;
592 }
593 buf[data_length++] = '\0';
594
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800595 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
596 return false;
597 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700598 return sc.CopyDone(lpath, rpath);
599#endif
600 }
601
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700602 struct stat st;
603 if (stat(lpath, &st) == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700604 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700605 return false;
606 }
607 if (st.st_size < SYNC_DATA_MAX) {
608 std::string data;
Josh Gao94dc19f2016-09-14 16:13:50 -0700609 if (!android::base::ReadFileToString(lpath, &data, true)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700610 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700611 return false;
612 }
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800613 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
614 data.data(), data.size())) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700615 return false;
616 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700617 } else {
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800618 if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700619 return false;
620 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700621 }
622 return sc.CopyDone(lpath, rpath);
623}
624
Felipe Leme44a42672016-04-01 17:43:27 -0700625static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
626 const char* name=nullptr) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700627 unsigned size = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700628 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner76f2a932014-03-11 17:55:59 -0700629
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700630 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800631
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700632 adb_unlink(lpath);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700633 int lfd = adb_creat(lpath, 0644);
634 if (lfd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700635 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700636 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800637 }
638
Elliott Hughesb708d162015-10-27 16:03:15 -0700639 uint64_t bytes_copied = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700640 while (true) {
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700641 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700642 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700643 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700644 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700645 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800646 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800647
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700648 if (msg.data.id == ID_DONE) break;
649
650 if (msg.data.id != ID_DATA) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800651 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700652 adb_unlink(lpath);
653 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700654 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800655 }
656
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700657 if (msg.data.size > sc.max) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700658 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 -0800659 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700660 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700661 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800662 }
663
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700664 char buffer[SYNC_DATA_MAX];
665 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800666 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700667 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700668 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800669 }
670
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700671 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700672 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700673 adb_close(lfd);
674 adb_unlink(lpath);
675 return false;
676 }
677
Elliott Hughesb708d162015-10-27 16:03:15 -0700678 bytes_copied += msg.data.size;
679
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700680 sc.RecordBytesTransferred(msg.data.size);
Josh Gao1286c1f2016-08-05 00:39:16 -0700681 sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800682 }
683
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700684 sc.RecordFilesTransferred(1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800685 adb_close(lfd);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700686 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800687}
688
Elliott Hughesaa245492015-08-03 10:38:08 -0700689bool do_sync_ls(const char* path) {
690 SyncConnection sc;
691 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800692
Josh Gaocda6a2b2015-11-02 16:45:47 -0800693 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
694 const char* name) {
695 printf("%08x %08x %08x %s\n", mode, size, time, name);
696 });
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800697}
698
Elliott Hughesaa245492015-08-03 10:38:08 -0700699static bool IsDotOrDotDot(const char* name) {
700 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
701}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800702
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800703static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800704 const std::string& lpath,
705 const std::string& rpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800706 std::vector<copyinfo> dirlist;
Josh Gaod9731572015-11-03 15:23:03 -0800707 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
Elliott Hughesaa245492015-08-03 10:38:08 -0700708 if (!dir) {
Josh Gaod9731572015-11-03 15:23:03 -0800709 sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800710 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800711 }
712
Josh Gao65800962015-11-04 14:57:04 -0800713 bool empty_dir = true;
Elliott Hughesb708d162015-10-27 16:03:15 -0700714 dirent* de;
Elliott Hughesaa245492015-08-03 10:38:08 -0700715 while ((de = readdir(dir.get()))) {
Josh Gao65800962015-11-04 14:57:04 -0800716 if (IsDotOrDotDot(de->d_name)) {
717 continue;
718 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700719
Josh Gao65800962015-11-04 14:57:04 -0800720 empty_dir = false;
Josh Gaod9731572015-11-03 15:23:03 -0800721 std::string stat_path = lpath + de->d_name;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800722
Elliott Hughesaa245492015-08-03 10:38:08 -0700723 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800724 if (lstat(stat_path.c_str(), &st) == -1) {
Josh Gaod9731572015-11-03 15:23:03 -0800725 sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
726 strerror(errno));
Josh Gao12a2ae92015-11-07 15:27:26 -0800727 continue;
728 }
729
Josh Gaof2642242015-12-09 14:03:30 -0800730 copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
Josh Gao12a2ae92015-11-07 15:27:26 -0800731 if (S_ISDIR(st.st_mode)) {
732 dirlist.push_back(ci);
733 } else {
Josh Gao48bc0d72016-03-02 16:11:13 -0800734 if (!should_push_file(st.st_mode)) {
735 sc.Warning("skipping special file '%s' (mode = 0o%o)", lpath.c_str(), st.st_mode);
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800736 ci.skip = true;
Josh Gao12a2ae92015-11-07 15:27:26 -0800737 }
Josh Gao48bc0d72016-03-02 16:11:13 -0800738 ci.time = st.st_mtime;
739 ci.size = st.st_size;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800740 file_list->push_back(ci);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800741 }
742 }
743
Elliott Hughesaa245492015-08-03 10:38:08 -0700744 // Close this directory and recurse.
745 dir.reset();
Josh Gao65800962015-11-04 14:57:04 -0800746
747 // Add the current directory to the list if it was empty, to ensure that
748 // it gets created.
749 if (empty_dir) {
750 // TODO(b/25566053): Make pushing empty directories work.
751 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao21abf5a2015-11-07 17:18:44 -0800752 sc.Warning("skipping empty directory '%s'", lpath.c_str());
Josh Gaof2642242015-12-09 14:03:30 -0800753 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
Josh Gao65800962015-11-04 14:57:04 -0800754 ci.skip = true;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800755 file_list->push_back(ci);
Josh Gao65800962015-11-04 14:57:04 -0800756 return true;
757 }
758
Josh Gaocda6a2b2015-11-02 16:45:47 -0800759 for (const copyinfo& ci : dirlist) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800760 local_build_list(sc, file_list, ci.lpath, ci.rpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800761 }
762
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800763 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800764}
765
Josh Gaod9731572015-11-03 15:23:03 -0800766static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
767 std::string rpath, bool check_timestamps,
768 bool list_only) {
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700769 sc.NewTransfer();
770
Josh Gaod9731572015-11-03 15:23:03 -0800771 // Make sure that both directory paths end in a slash.
Josh Gao1a025302015-11-09 11:12:14 -0800772 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800773 ensure_trailing_separators(lpath, rpath);
Josh Gaod9731572015-11-03 15:23:03 -0800774
775 // Recursively build the list of files to copy.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800776 std::vector<copyinfo> file_list;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800777 int skipped = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800778 if (!local_build_list(sc, &file_list, lpath, rpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700779 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800780 }
781
Elliott Hughesaa245492015-08-03 10:38:08 -0700782 if (check_timestamps) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800783 for (const copyinfo& ci : file_list) {
Josh Gao1a025302015-11-09 11:12:14 -0800784 if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
Josh Gaod9731572015-11-03 15:23:03 -0800785 return false;
786 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800787 }
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800788 for (copyinfo& ci : file_list) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800789 unsigned int timestamp, mode, size;
Josh Gaod9731572015-11-03 15:23:03 -0800790 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
791 return false;
792 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800793 if (size == ci.size) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800794 // For links, we cannot update the atime/mtime.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800795 if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
796 (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800797 ci.skip = true;
Elliott Hughesaa245492015-08-03 10:38:08 -0700798 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800799 }
800 }
801 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800802
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800803 sc.ComputeExpectedTotalBytes(file_list);
804
805 for (const copyinfo& ci : file_list) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800806 if (!ci.skip) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700807 if (list_only) {
Josh Gaobaa215e2016-08-04 14:55:23 -0700808 sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
Elliott Hughesb708d162015-10-27 16:03:15 -0700809 } else {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800810 if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) {
Josh Gaod9731572015-11-03 15:23:03 -0800811 return false;
Elliott Hughesb708d162015-10-27 16:03:15 -0700812 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800813 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800814 } else {
815 skipped++;
816 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800817 }
818
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700819 sc.RecordFilesSkipped(skipped);
820 sc.ReportTransferRate(lpath, TransferDirection::push);
Elliott Hughesaa245492015-08-03 10:38:08 -0700821 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800822}
823
Josh Gao05786772015-10-30 16:57:19 -0700824bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700825 SyncConnection sc;
826 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800827
Josh Gao05786772015-10-30 16:57:19 -0700828 bool success = true;
Josh Gao12a2ae92015-11-07 15:27:26 -0800829 unsigned dst_mode;
830 if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false;
831 bool dst_exists = (dst_mode != 0);
Josh Gao07db1192015-11-07 15:38:19 -0800832 bool dst_isdir = S_ISDIR(dst_mode);
Josh Gao05786772015-10-30 16:57:19 -0700833
Josh Gao07db1192015-11-07 15:38:19 -0800834 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700835 if (srcs.size() > 1) {
836 sc.Error("target '%s' is not a directory", dst);
837 return false;
838 } else {
839 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -0800840
841 // A path that ends with a slash doesn't have to be a directory if
842 // it doesn't exist yet.
843 if (dst[dst_len - 1] == '/' && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -0700844 sc.Error("failed to access '%s': Not a directory", dst);
845 return false;
846 }
847 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700848 }
Josh Gao05786772015-10-30 16:57:19 -0700849
850 for (const char* src_path : srcs) {
851 const char* dst_path = dst;
852 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800853 if (stat(src_path, &st) == -1) {
Josh Gao05786772015-10-30 16:57:19 -0700854 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
855 success = false;
856 continue;
857 }
858
859 if (S_ISDIR(st.st_mode)) {
Josh Gao07db1192015-11-07 15:38:19 -0800860 std::string dst_dir = dst;
861
862 // If the destination path existed originally, the source directory
863 // should be copied as a child of the destination.
864 if (dst_exists) {
865 if (!dst_isdir) {
866 sc.Error("target '%s' is not a directory", dst);
867 return false;
868 }
869 // dst is a POSIX path, so we don't want to use the sysdeps
870 // helpers here.
871 if (dst_dir.back() != '/') {
872 dst_dir.push_back('/');
873 }
874 dst_dir.append(adb_basename(src_path));
875 }
876
877 success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(),
878 false, false);
Josh Gao05786772015-10-30 16:57:19 -0700879 continue;
Josh Gao48bc0d72016-03-02 16:11:13 -0800880 } else if (!should_push_file(st.st_mode)) {
881 sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
882 continue;
Josh Gao05786772015-10-30 16:57:19 -0700883 }
884
885 std::string path_holder;
Josh Gao07db1192015-11-07 15:38:19 -0800886 if (dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700887 // If we're copying a local file to a remote directory,
888 // we really want to copy to remote_dir + "/" + local_filename.
Josh Gao323899b2016-02-03 14:55:24 -0800889 path_holder = dst_path;
890 if (path_holder.back() != '/') {
891 path_holder.push_back('/');
892 }
893 path_holder += adb_basename(src_path);
Josh Gao05786772015-10-30 16:57:19 -0700894 dst_path = path_holder.c_str();
895 }
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700896
897 sc.NewTransfer();
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800898 sc.SetExpectedTotalBytes(st.st_size);
Josh Gao05786772015-10-30 16:57:19 -0700899 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700900 sc.ReportTransferRate(src_path, TransferDirection::push);
Josh Gao05786772015-10-30 16:57:19 -0700901 }
902
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700903 sc.ReportOverallTransferRate(TransferDirection::push);
Josh Gao05786772015-10-30 16:57:19 -0700904 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800905}
906
Josh Gaof2642242015-12-09 14:03:30 -0800907static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) {
908 unsigned mode;
909 std::string dir_path = rpath;
910 dir_path.push_back('/');
911 if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) {
912 sc.Error("failed to stat remote symlink '%s'", dir_path.c_str());
913 return false;
914 }
915 return S_ISDIR(mode);
916}
917
Josh Gaoa63b17f2016-02-25 17:12:45 -0800918static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
919 const std::string& rpath, const std::string& lpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800920 std::vector<copyinfo> dirlist;
Josh Gaof2642242015-12-09 14:03:30 -0800921 std::vector<copyinfo> linklist;
Josh Gaoa63b17f2016-02-25 17:12:45 -0800922
923 // Add an entry for the current directory to ensure it gets created before pulling its contents.
Josh Gao379612b2016-03-02 16:00:02 -0800924 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
Josh Gaoa63b17f2016-02-25 17:12:45 -0800925 file_list->push_back(ci);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800926
Elliott Hughesaa245492015-08-03 10:38:08 -0700927 // Put the files/dirs in rpath on the lists.
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800928 auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
Josh Gao65800962015-11-04 14:57:04 -0800929 if (IsDotOrDotDot(name)) {
930 return;
931 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800932
Josh Gaof2642242015-12-09 14:03:30 -0800933 copyinfo ci(lpath, rpath, name, mode);
Josh Gao65800962015-11-04 14:57:04 -0800934 if (S_ISDIR(mode)) {
935 dirlist.push_back(ci);
Josh Gaof2642242015-12-09 14:03:30 -0800936 } else if (S_ISLNK(mode)) {
937 linklist.push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -0800938 } else {
Josh Gao48bc0d72016-03-02 16:11:13 -0800939 if (!should_pull_file(ci.mode)) {
940 sc.Warning("skipping special file '%s' (mode = 0o%o)", ci.rpath.c_str(), ci.mode);
941 ci.skip = true;
942 }
Josh Gaof2642242015-12-09 14:03:30 -0800943 ci.time = time;
944 ci.size = size;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800945 file_list->push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -0800946 }
947 };
948
Josh Gaod9731572015-11-03 15:23:03 -0800949 if (!sync_ls(sc, rpath.c_str(), callback)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700950 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800951 }
952
Josh Gaof2642242015-12-09 14:03:30 -0800953 // Check each symlink we found to see whether it's a file or directory.
954 for (copyinfo& link_ci : linklist) {
955 if (remote_symlink_isdir(sc, link_ci.rpath)) {
956 dirlist.emplace_back(std::move(link_ci));
957 } else {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800958 file_list->emplace_back(std::move(link_ci));
Josh Gaof2642242015-12-09 14:03:30 -0800959 }
960 }
961
Elliott Hughesaa245492015-08-03 10:38:08 -0700962 // Recurse into each directory we found.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800963 while (!dirlist.empty()) {
964 copyinfo current = dirlist.back();
965 dirlist.pop_back();
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800966 if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700967 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800968 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800969 }
970
Elliott Hughesaa245492015-08-03 10:38:08 -0700971 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800972}
973
Josh Gao1a025302015-11-09 11:12:14 -0800974static int set_time_and_mode(const std::string& lpath, time_t time,
975 unsigned int mode) {
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700976 struct utimbuf times = { time, time };
Josh Gao1a025302015-11-09 11:12:14 -0800977 int r1 = utime(lpath.c_str(), &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700978
979 /* use umask for permissions */
Josh Gaocda6a2b2015-11-02 16:45:47 -0800980 mode_t mask = umask(0000);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700981 umask(mask);
Josh Gao1a025302015-11-09 11:12:14 -0800982 int r2 = chmod(lpath.c_str(), mode & ~mask);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700983
Spencer Low363af562015-11-07 18:51:54 -0800984 return r1 ? r1 : r2;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700985}
986
Josh Gaod9731572015-11-03 15:23:03 -0800987static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
988 std::string lpath, bool copy_attrs) {
Josh Gaofb0c5cb2016-08-04 14:53:17 -0700989 sc.NewTransfer();
990
Elliott Hughesaa245492015-08-03 10:38:08 -0700991 // Make sure that both directory paths end in a slash.
Josh Gao12a2ae92015-11-07 15:27:26 -0800992 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800993 ensure_trailing_separators(lpath, rpath);
Riley Andrews4d04d242014-12-12 13:12:36 -0800994
Elliott Hughesaa245492015-08-03 10:38:08 -0700995 // Recursively build the list of files to copy.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800996 sc.Printf("pull: building file list...");
997 std::vector<copyinfo> file_list;
998 if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800999 return false;
1000 }
Elliott Hughesaa245492015-08-03 10:38:08 -07001001
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001002 sc.ComputeExpectedTotalBytes(file_list);
1003
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001004 int skipped = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001005 for (const copyinfo &ci : file_list) {
Josh Gaofc7c3b62015-11-03 14:44:04 -08001006 if (!ci.skip) {
Josh Gao65800962015-11-04 14:57:04 -08001007 if (S_ISDIR(ci.mode)) {
1008 // Entry is for an empty directory, create it and continue.
1009 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao1a025302015-11-09 11:12:14 -08001010 if (!mkdirs(ci.lpath)) {
Josh Gao65800962015-11-04 14:57:04 -08001011 sc.Error("failed to create directory '%s': %s",
Josh Gao1a025302015-11-09 11:12:14 -08001012 ci.lpath.c_str(), strerror(errno));
Josh Gao65800962015-11-04 14:57:04 -08001013 return false;
1014 }
Josh Gao65800962015-11-04 14:57:04 -08001015 continue;
1016 }
1017
Josh Gao1a025302015-11-09 11:12:14 -08001018 if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001019 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001020 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001021
Josh Gao1a025302015-11-09 11:12:14 -08001022 if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001023 return false;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -07001024 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001025 } else {
1026 skipped++;
1027 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001028 }
1029
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001030 sc.RecordFilesSkipped(skipped);
1031 sc.ReportTransferRate(rpath, TransferDirection::pull);
Elliott Hughesaa245492015-08-03 10:38:08 -07001032 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001033}
1034
Josh Gao05786772015-10-30 16:57:19 -07001035bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
Felipe Leme44a42672016-04-01 17:43:27 -07001036 bool copy_attrs, const char* name) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001037 SyncConnection sc;
1038 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001039
Josh Gao05786772015-10-30 16:57:19 -07001040 bool success = true;
Josh Gao05786772015-10-30 16:57:19 -07001041 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -08001042 bool dst_exists = true;
1043
1044 if (stat(dst, &st) == -1) {
1045 dst_exists = false;
1046
1047 // If we're only pulling one path, the destination path might point to
Josh Gao05786772015-10-30 16:57:19 -07001048 // a path that doesn't exist yet.
Josh Gao12a2ae92015-11-07 15:27:26 -08001049 if (srcs.size() == 1 && errno == ENOENT) {
1050 // However, its parent must exist.
1051 struct stat parent_st;
1052 if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
1053 sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
1054 return false;
1055 }
1056 } else {
1057 sc.Error("failed to access '%s': %s", dst, strerror(errno));
Josh Gao05786772015-10-30 16:57:19 -07001058 return false;
1059 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001060 }
1061
Josh Gao07db1192015-11-07 15:38:19 -08001062 bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
1063 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -07001064 if (srcs.size() > 1) {
1065 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -07001066 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001067 } else {
Josh Gao05786772015-10-30 16:57:19 -07001068 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -08001069
1070 // A path that ends with a slash doesn't have to be a directory if
1071 // it doesn't exist yet.
Josh Gao1a025302015-11-09 11:12:14 -08001072 if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -07001073 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -07001074 return false;
Elliott Hughes5c742702015-07-30 17:42:01 -07001075 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001076 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001077 }
Elliott Hughesaa245492015-08-03 10:38:08 -07001078
Josh Gao05786772015-10-30 16:57:19 -07001079 for (const char* src_path : srcs) {
1080 const char* dst_path = dst;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001081 unsigned src_mode, src_time, src_size;
1082 if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) {
Josh Gaof2642242015-12-09 14:03:30 -08001083 sc.Error("failed to stat remote object '%s'", src_path);
Josh Gao12a2ae92015-11-07 15:27:26 -08001084 return false;
1085 }
1086 if (src_mode == 0) {
Josh Gao05786772015-10-30 16:57:19 -07001087 sc.Error("remote object '%s' does not exist", src_path);
1088 success = false;
1089 continue;
1090 }
1091
Josh Gaof2642242015-12-09 14:03:30 -08001092 bool src_isdir = S_ISDIR(src_mode);
1093 if (S_ISLNK(src_mode)) {
1094 src_isdir = remote_symlink_isdir(sc, src_path);
1095 }
1096
Josh Gaof2642242015-12-09 14:03:30 -08001097 if (src_isdir) {
Josh Gao07db1192015-11-07 15:38:19 -08001098 std::string dst_dir = dst;
1099
1100 // If the destination path existed originally, the source directory
1101 // should be copied as a child of the destination.
1102 if (dst_exists) {
1103 if (!dst_isdir) {
1104 sc.Error("target '%s' is not a directory", dst);
1105 return false;
1106 }
1107 if (!adb_is_separator(dst_dir.back())) {
1108 dst_dir.push_back(OS_PATH_SEPARATOR);
1109 }
1110 dst_dir.append(adb_basename(src_path));
1111 }
1112
Josh Gaof2642242015-12-09 14:03:30 -08001113 success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
Josh Gao05786772015-10-30 16:57:19 -07001114 continue;
Josh Gao48bc0d72016-03-02 16:11:13 -08001115 } else if (!should_pull_file(src_mode)) {
1116 sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_mode);
1117 continue;
1118 }
Josh Gaof2642242015-12-09 14:03:30 -08001119
Josh Gao48bc0d72016-03-02 16:11:13 -08001120 std::string path_holder;
1121 if (dst_isdir) {
1122 // If we're copying a remote file to a local directory, we
1123 // really want to copy to local_dir + OS_PATH_SEPARATOR +
1124 // basename(remote).
1125 path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
1126 adb_basename(src_path).c_str());
1127 dst_path = path_holder.c_str();
1128 }
Josh Gaof2642242015-12-09 14:03:30 -08001129
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001130 sc.NewTransfer();
Josh Gao48bc0d72016-03-02 16:11:13 -08001131 sc.SetExpectedTotalBytes(src_size);
Felipe Leme44a42672016-04-01 17:43:27 -07001132 if (!sync_recv(sc, src_path, dst_path, name)) {
Josh Gao48bc0d72016-03-02 16:11:13 -08001133 success = false;
1134 continue;
1135 }
1136
1137 if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) {
1138 success = false;
1139 continue;
Josh Gao05786772015-10-30 16:57:19 -07001140 }
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001141 sc.ReportTransferRate(src_path, TransferDirection::pull);
Josh Gao05786772015-10-30 16:57:19 -07001142 }
1143
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001144 sc.ReportOverallTransferRate(TransferDirection::pull);
Josh Gao05786772015-10-30 16:57:19 -07001145 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001146}
1147
Elliott Hughesaa245492015-08-03 10:38:08 -07001148bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001149 SyncConnection sc;
1150 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001151
Josh Gaofb0c5cb2016-08-04 14:53:17 -07001152 bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only);
1153 if (!list_only) {
1154 sc.ReportOverallTransferRate(TransferDirection::push);
1155 }
1156 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001157}