blob: 12c78378768363432360ec0425e5f35f8d690541 [file] [log] [blame]
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Dan Albertb302d122015-02-24 15:51:19 -080017#include <dirent.h>
18#include <errno.h>
Spencer Low803451e2015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albertb302d122015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albertb302d122015-02-24 15:51:19 -080027#include <time.h>
Elliott Hughesdde00be2015-09-27 12:55:37 -070028#include <unistd.h>
Greg Hackmann8b689142014-05-06 08:48:18 -070029#include <utime.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080030
Josh Gao204d21e2015-11-02 16:45:47 -080031#include <functional>
Elliott Hughes4e7848d2015-08-24 14:49:43 -070032#include <memory>
Elliott Hughes6c73bfc2015-10-27 13:40:35 -070033#include <vector>
Elliott Hughes4e7848d2015-08-24 14:49:43 -070034
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080035#include "sysdeps.h"
Dan Albertb302d122015-02-24 15:51:19 -080036
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080037#include "adb.h"
38#include "adb_client.h"
Dan Albert66a91b02015-02-24 21:26:58 -080039#include "adb_io.h"
Alex Valléee9163152015-05-06 17:22:25 -040040#include "adb_utils.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080041#include "file_sync_service.h"
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070042#include "line_printer.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080043
Elliott Hughesf55ead92015-12-04 22:00:26 -080044#include <android-base/file.h>
45#include <android-base/strings.h>
46#include <android-base/stringprintf.h>
Elliott Hughesd189cfb2015-07-30 17:42:01 -070047
Elliott Hughesb628cb12015-08-03 10:38:08 -070048struct syncsendbuf {
49 unsigned id;
50 unsigned size;
51 char data[SYNC_DATA_MAX];
52};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080053
Elliott Hughes7b43fa52015-12-17 17:05:29 -080054static void ensure_trailing_separators(std::string& local_path, std::string& remote_path) {
55 if (!adb_is_separator(local_path.back())) {
56 local_path.push_back(OS_PATH_SEPARATOR);
57 }
58 if (remote_path.back() != '/') {
59 remote_path.push_back('/');
60 }
61}
62
Josh Gaocaa52102016-03-02 16:11:13 -080063static bool should_pull_file(mode_t mode) {
64 return mode & (S_IFREG | S_IFBLK | S_IFCHR);
65}
66
67static bool should_push_file(mode_t mode) {
68 mode_t mask = S_IFREG;
69#if !defined(_WIN32)
70 mask |= S_IFLNK;
71#endif
72 return mode & mask;
73}
74
Elliott Hughes7b43fa52015-12-17 17:05:29 -080075struct copyinfo {
76 std::string lpath;
77 std::string rpath;
78 unsigned int time = 0;
79 unsigned int mode;
80 uint64_t size = 0;
81 bool skip = false;
82
83 copyinfo(const std::string& local_path,
84 const std::string& remote_path,
85 const std::string& name,
86 unsigned int mode)
87 : lpath(local_path), rpath(remote_path), mode(mode) {
88 ensure_trailing_separators(lpath, rpath);
89 lpath.append(name);
90 rpath.append(name);
91 if (S_ISDIR(mode)) {
92 ensure_trailing_separators(lpath, rpath);
93 }
94 }
95};
96
Elliott Hughesb628cb12015-08-03 10:38:08 -070097class SyncConnection {
98 public:
Elliott Hughes7b43fa52015-12-17 17:05:29 -080099 SyncConnection()
100 : total_bytes_(0),
101 start_time_ms_(CurrentTimeMs()),
102 expected_total_bytes_(0),
Josh Gaoa53abe72016-02-19 15:55:55 -0800103 expect_multiple_files_(false),
104 expect_done_(false) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700105 max = SYNC_DATA_MAX; // TODO: decide at runtime.
106
107 std::string error;
108 fd = adb_connect("sync:", &error);
109 if (fd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700110 Error("connect failed: %s", error.c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -0700111 }
112 }
113
114 ~SyncConnection() {
115 if (!IsValid()) return;
116
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700117 if (SendQuit()) {
118 // We sent a quit command, so the server should be doing orderly
119 // shutdown soon. But if we encountered an error while we were using
120 // the connection, the server might still be sending data (before
121 // doing orderly shutdown), in which case we won't wait for all of
122 // the data nor the coming orderly shutdown. In the common success
123 // case, this will wait for the server to do orderly shutdown.
124 ReadOrderlyShutdown(fd);
125 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700126 adb_close(fd);
Elliott Hughes78a37a52015-12-08 16:01:15 -0800127
128 line_printer_.KeepInfoLine();
Elliott Hughesb628cb12015-08-03 10:38:08 -0700129 }
130
131 bool IsValid() { return fd >= 0; }
132
Josh Gaoa53abe72016-02-19 15:55:55 -0800133 bool ReceivedError(const char* from, const char* to) {
134 adb_pollfd pfd = {.fd = fd, .events = POLLIN};
135 int rc = adb_poll(&pfd, 1, 0);
136 if (rc < 0) {
137 Error("failed to poll: %s", strerror(errno));
138 return true;
139 }
140 return rc != 0;
141 }
142
Elliott Hughesdde00be2015-09-27 12:55:37 -0700143 bool SendRequest(int id, const char* path_and_mode) {
144 size_t path_length = strlen(path_and_mode);
145 if (path_length > 1024) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700146 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700147 errno = ENAMETOOLONG;
148 return false;
149 }
150
151 // Sending header and payload in a single write makes a noticeable
152 // difference to "adb sync" performance.
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700153 std::vector<char> buf(sizeof(SyncRequest) + path_length);
154 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700155 req->id = id;
156 req->path_length = path_length;
157 char* data = reinterpret_cast<char*>(req + 1);
158 memcpy(data, path_and_mode, path_length);
159
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700160 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesdde00be2015-09-27 12:55:37 -0700161 }
162
163 // Sending header, payload, and footer in a single write makes a huge
164 // difference to "adb sync" performance.
165 bool SendSmallFile(const char* path_and_mode,
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800166 const char* lpath, const char* rpath,
Elliott Hughes7275d802015-11-20 17:35:17 -0800167 unsigned mtime,
168 const char* data, size_t data_length) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700169 size_t path_length = strlen(path_and_mode);
170 if (path_length > 1024) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700171 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700172 errno = ENAMETOOLONG;
173 return false;
174 }
175
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700176 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughes7275d802015-11-20 17:35:17 -0800177 sizeof(SyncRequest) + data_length +
178 sizeof(SyncRequest));
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700179 char* p = &buf[0];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700180
181 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
182 req_send->id = ID_SEND;
183 req_send->path_length = path_length;
184 p += sizeof(SyncRequest);
185 memcpy(p, path_and_mode, path_length);
186 p += path_length;
187
188 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
189 req_data->id = ID_DATA;
190 req_data->path_length = data_length;
191 p += sizeof(SyncRequest);
192 memcpy(p, data, data_length);
193 p += data_length;
194
195 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
196 req_done->id = ID_DONE;
197 req_done->path_length = mtime;
198 p += sizeof(SyncRequest);
199
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800200 WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
Josh Gaoa53abe72016-02-19 15:55:55 -0800201 expect_done_ = true;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800202 total_bytes_ += data_length;
Josh Gao93a0b3c2016-03-01 11:46:02 -0800203 ReportProgress(rpath, data_length, data_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700204 return true;
205 }
206
Elliott Hughes7275d802015-11-20 17:35:17 -0800207 bool SendLargeFile(const char* path_and_mode,
208 const char* lpath, const char* rpath,
209 unsigned mtime) {
210 if (!SendRequest(ID_SEND, path_and_mode)) {
211 Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
212 return false;
213 }
214
215 struct stat st;
216 if (stat(lpath, &st) == -1) {
217 Error("cannot stat '%s': %s", lpath, strerror(errno));
218 return false;
219 }
220
221 uint64_t total_size = st.st_size;
222 uint64_t bytes_copied = 0;
223
224 int lfd = adb_open(lpath, O_RDONLY);
225 if (lfd < 0) {
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800226 Error("opening '%s' locally failed: %s", lpath, strerror(errno));
Elliott Hughes7275d802015-11-20 17:35:17 -0800227 return false;
228 }
229
230 syncsendbuf sbuf;
231 sbuf.id = ID_DATA;
232 while (true) {
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800233 int bytes_read = adb_read(lfd, sbuf.data, max);
234 if (bytes_read == -1) {
235 Error("reading '%s' locally failed: %s", lpath, strerror(errno));
236 adb_close(lfd);
237 return false;
238 } else if (bytes_read == 0) {
Elliott Hughes7275d802015-11-20 17:35:17 -0800239 break;
240 }
241
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800242 sbuf.size = bytes_read;
243 WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
Elliott Hughes7275d802015-11-20 17:35:17 -0800244
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800245 total_bytes_ += bytes_read;
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800246 bytes_copied += bytes_read;
Elliott Hughes7275d802015-11-20 17:35:17 -0800247
Josh Gaoa53abe72016-02-19 15:55:55 -0800248 // Check to see if we've received an error from the other side.
249 if (ReceivedError(lpath, rpath)) {
250 break;
251 }
252
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800253 ReportProgress(rpath, bytes_copied, total_size);
Elliott Hughes7275d802015-11-20 17:35:17 -0800254 }
255
256 adb_close(lfd);
257
258 syncmsg msg;
259 msg.data.id = ID_DONE;
260 msg.data.size = mtime;
Josh Gaoa53abe72016-02-19 15:55:55 -0800261 expect_done_ = true;
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800262 return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
Elliott Hughes7275d802015-11-20 17:35:17 -0800263 }
264
Elliott Hughesdde00be2015-09-27 12:55:37 -0700265 bool CopyDone(const char* from, const char* to) {
266 syncmsg msg;
267 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Josh Gaoa53abe72016-02-19 15:55:55 -0800268 Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700269 return false;
270 }
271 if (msg.status.id == ID_OKAY) {
Josh Gaoa53abe72016-02-19 15:55:55 -0800272 if (expect_done_) {
273 expect_done_ = false;
274 return true;
275 } else {
276 Error("failed to copy '%s' to '%s': received premature success", from, to);
277 return true;
278 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700279 }
280 if (msg.status.id != ID_FAIL) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700281 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700282 return false;
283 }
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700284 return ReportCopyFailure(from, to, msg);
285 }
286
287 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700288 std::vector<char> buf(msg.status.msglen + 1);
289 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700290 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
291 from, to, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700292 return false;
293 }
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700294 buf[msg.status.msglen] = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700295 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700296 return false;
297 }
298
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700299 std::string TransferRate() {
300 uint64_t ms = CurrentTimeMs() - start_time_ms_;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800301 if (total_bytes_ == 0 || ms == 0) return "";
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700302
303 double s = static_cast<double>(ms) / 1000LL;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800304 double rate = (static_cast<double>(total_bytes_) / s) / (1024*1024);
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700305 return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800306 rate, total_bytes_, s);
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700307 }
308
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800309 void ReportProgress(const char* file, uint64_t file_copied_bytes, uint64_t file_total_bytes) {
310 char overall_percentage_str[5] = "?";
311 if (expected_total_bytes_ != 0) {
312 int overall_percentage = static_cast<int>(total_bytes_ * 100 / expected_total_bytes_);
313 // If we're pulling symbolic links, we'll pull the target of the link rather than
314 // just create a local link, and that will cause us to go over 100%.
315 if (overall_percentage <= 100) {
316 snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
317 overall_percentage);
318 }
319 }
320
321 if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
322 // This case can happen if we're racing against something that wrote to the file
323 // between our stat and our read, or if we're reading a magic file that lies about
324 // its size. Just show how much we've copied.
325 Printf("[%4s] %s: %" PRId64 "/?", overall_percentage_str, file, file_copied_bytes);
326 } else {
327 // If we're transferring multiple files, we want to know how far through the current
328 // file we are, as well as the overall percentage.
329 if (expect_multiple_files_) {
330 int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
331 Printf("[%4s] %s: %d%%", overall_percentage_str, file, file_percentage);
332 } else {
333 Printf("[%4s] %s", overall_percentage_str, file);
334 }
335 }
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700336 }
337
Josh Gaocbf485f2015-11-02 17:15:57 -0800338 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
339 std::string s;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800340
Josh Gaocbf485f2015-11-02 17:15:57 -0800341 va_list ap;
342 va_start(ap, fmt);
343 android::base::StringAppendV(&s, fmt, ap);
344 va_end(ap);
345
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800346 line_printer_.Print(s, LinePrinter::INFO);
Josh Gaocbf485f2015-11-02 17:15:57 -0800347 }
348
Josh Gaof35fede2016-08-04 11:43:00 -0700349 void Println(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
350 std::string s;
351
352 va_list ap;
353 va_start(ap, fmt);
354 android::base::StringAppendV(&s, fmt, ap);
355 va_end(ap);
356
357 line_printer_.Print(s, LinePrinter::INFO);
358 line_printer_.KeepInfoLine();
359 }
360
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700361 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
362 std::string s = "adb: error: ";
363
364 va_list ap;
365 va_start(ap, fmt);
366 android::base::StringAppendV(&s, fmt, ap);
367 va_end(ap);
368
Elliott Hughes78a37a52015-12-08 16:01:15 -0800369 line_printer_.Print(s, LinePrinter::ERROR);
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700370 }
371
Josh Gaoa544cc62015-11-07 17:18:44 -0800372 void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
373 std::string s = "adb: warning: ";
374
375 va_list ap;
376 va_start(ap, fmt);
377 android::base::StringAppendV(&s, fmt, ap);
378 va_end(ap);
379
Elliott Hughes78a37a52015-12-08 16:01:15 -0800380 line_printer_.Print(s, LinePrinter::WARNING);
Josh Gaoa544cc62015-11-07 17:18:44 -0800381 }
382
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800383 void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
384 expected_total_bytes_ = 0;
385 for (const copyinfo& ci : file_list) {
386 // Unfortunately, this doesn't work for symbolic links, because we'll copy the
387 // target of the link rather than just creating a link. (But ci.size is the link size.)
388 if (!ci.skip) expected_total_bytes_ += ci.size;
389 }
390 expect_multiple_files_ = true;
391 }
392
393 void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
394 expected_total_bytes_ = expected_total_bytes;
395 expect_multiple_files_ = false;
396 }
397
398 uint64_t total_bytes_;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700399
400 // TODO: add a char[max] buffer here, to replace syncsendbuf...
401 int fd;
402 size_t max;
403
404 private:
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700405 uint64_t start_time_ms_;
406
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800407 uint64_t expected_total_bytes_;
408 bool expect_multiple_files_;
Josh Gaoa53abe72016-02-19 15:55:55 -0800409 bool expect_done_;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800410
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700411 LinePrinter line_printer_;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700412
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700413 bool SendQuit() {
414 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesb628cb12015-08-03 10:38:08 -0700415 }
416
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800417 bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
418 if (!WriteFdExactly(fd, data, data_length)) {
419 if (errno == ECONNRESET) {
420 // Assume adbd told us why it was closing the connection, and
421 // try to read failure reason from adbd.
422 syncmsg msg;
423 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
424 Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
425 } else if (msg.status.id != ID_FAIL) {
426 Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
427 } else {
428 ReportCopyFailure(from, to, msg);
429 }
430 } else {
431 Error("%zu-byte write failed: %s", data_length, strerror(errno));
432 }
433 _exit(1);
434 }
435 return true;
436 }
437
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700438 static uint64_t CurrentTimeMs() {
439 struct timeval tv;
440 gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
441 return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700442 }
443};
444
Josh Gao204d21e2015-11-02 16:45:47 -0800445typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700446
Josh Gao204d21e2015-11-02 16:45:47 -0800447static bool sync_ls(SyncConnection& sc, const char* path,
Chih-Hung Hsieh90b40f62016-07-27 16:25:51 -0700448 const std::function<sync_ls_cb>& func) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700449 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700450
451 while (true) {
452 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700453 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700454
455 if (msg.dent.id == ID_DONE) return true;
456 if (msg.dent.id != ID_DENT) return false;
457
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700458 size_t len = msg.dent.namelen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700459 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800460
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700461 char buf[257];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700462 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800463 buf[len] = 0;
464
Josh Gao204d21e2015-11-02 16:45:47 -0800465 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800466 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800467}
468
Elliott Hughesb628cb12015-08-03 10:38:08 -0700469static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
470 unsigned int* mode, unsigned int* size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800471 syncmsg msg;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700472 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
473 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800474 }
475
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700476 if (timestamp) *timestamp = msg.stat.time;
477 if (mode) *mode = msg.stat.mode;
478 if (size) *size = msg.stat.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800479
Elliott Hughesb628cb12015-08-03 10:38:08 -0700480 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800481}
482
Elliott Hughesb628cb12015-08-03 10:38:08 -0700483static bool sync_stat(SyncConnection& sc, const char* path,
484 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700485 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800486}
487
Elliott Hughesdde00be2015-09-27 12:55:37 -0700488static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700489 unsigned mtime, mode_t mode)
Elliott Hughesdde00be2015-09-27 12:55:37 -0700490{
491 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
492
493 if (S_ISLNK(mode)) {
494#if !defined(_WIN32)
495 char buf[PATH_MAX];
496 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
497 if (data_length == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700498 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700499 return false;
500 }
501 buf[data_length++] = '\0';
502
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800503 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
504 return false;
505 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700506 return sc.CopyDone(lpath, rpath);
507#endif
508 }
509
Elliott Hughesdde00be2015-09-27 12:55:37 -0700510 struct stat st;
511 if (stat(lpath, &st) == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700512 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700513 return false;
514 }
515 if (st.st_size < SYNC_DATA_MAX) {
516 std::string data;
517 if (!android::base::ReadFileToString(lpath, &data)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700518 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700519 return false;
520 }
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800521 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
522 data.data(), data.size())) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700523 return false;
524 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700525 } else {
Elliott Hughes7275d802015-11-20 17:35:17 -0800526 if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700527 return false;
528 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700529 }
530 return sc.CopyDone(lpath, rpath);
531}
532
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700533static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700534 unsigned size = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700535 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700536
Elliott Hughesdde00be2015-09-27 12:55:37 -0700537 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800538
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700539 adb_unlink(lpath);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700540 int lfd = adb_creat(lpath, 0644);
541 if (lfd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700542 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700543 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800544 }
545
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700546 uint64_t bytes_copied = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700547 while (true) {
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700548 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700549 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700550 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700551 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700552 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800553 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800554
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700555 if (msg.data.id == ID_DONE) break;
556
557 if (msg.data.id != ID_DATA) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800558 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700559 adb_unlink(lpath);
560 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700561 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800562 }
563
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700564 if (msg.data.size > sc.max) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700565 sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800566 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700567 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700568 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800569 }
570
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700571 char buffer[SYNC_DATA_MAX];
572 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800573 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700574 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700575 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800576 }
577
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700578 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700579 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700580 adb_close(lfd);
581 adb_unlink(lpath);
582 return false;
583 }
584
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800585 sc.total_bytes_ += msg.data.size;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700586
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700587 bytes_copied += msg.data.size;
588
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800589 sc.ReportProgress(rpath, bytes_copied, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800590 }
591
592 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700593 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800594}
595
Elliott Hughesb628cb12015-08-03 10:38:08 -0700596bool do_sync_ls(const char* path) {
597 SyncConnection sc;
598 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800599
Josh Gao204d21e2015-11-02 16:45:47 -0800600 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
601 const char* name) {
602 printf("%08x %08x %08x %s\n", mode, size, time, name);
603 });
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800604}
605
Elliott Hughesb628cb12015-08-03 10:38:08 -0700606static bool IsDotOrDotDot(const char* name) {
607 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
608}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800609
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800610static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
Josh Gao8efa6462015-11-03 15:26:38 -0800611 const std::string& lpath,
612 const std::string& rpath) {
Josh Gao204d21e2015-11-02 16:45:47 -0800613 std::vector<copyinfo> dirlist;
Josh Gaod20cf382015-11-03 15:23:03 -0800614 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700615 if (!dir) {
Josh Gaod20cf382015-11-03 15:23:03 -0800616 sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
Josh Gao8efa6462015-11-03 15:26:38 -0800617 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800618 }
619
Josh Gaoa90563e2015-11-04 14:57:04 -0800620 bool empty_dir = true;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700621 dirent* de;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700622 while ((de = readdir(dir.get()))) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800623 if (IsDotOrDotDot(de->d_name)) {
624 continue;
625 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700626
Josh Gaoa90563e2015-11-04 14:57:04 -0800627 empty_dir = false;
Josh Gaod20cf382015-11-03 15:23:03 -0800628 std::string stat_path = lpath + de->d_name;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800629
Elliott Hughesb628cb12015-08-03 10:38:08 -0700630 struct stat st;
Josh Gaoa5cea712015-11-07 15:27:26 -0800631 if (lstat(stat_path.c_str(), &st) == -1) {
Josh Gaod20cf382015-11-03 15:23:03 -0800632 sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
633 strerror(errno));
Josh Gaoa5cea712015-11-07 15:27:26 -0800634 continue;
635 }
636
Josh Gaod9a2fd62015-12-09 14:03:30 -0800637 copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
Josh Gaoa5cea712015-11-07 15:27:26 -0800638 if (S_ISDIR(st.st_mode)) {
639 dirlist.push_back(ci);
640 } else {
Josh Gaocaa52102016-03-02 16:11:13 -0800641 if (!should_push_file(st.st_mode)) {
642 sc.Warning("skipping special file '%s' (mode = 0o%o)", lpath.c_str(), st.st_mode);
Josh Gaob3cab932015-11-30 10:21:25 -0800643 ci.skip = true;
Josh Gaoa5cea712015-11-07 15:27:26 -0800644 }
Josh Gaocaa52102016-03-02 16:11:13 -0800645 ci.time = st.st_mtime;
646 ci.size = st.st_size;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800647 file_list->push_back(ci);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800648 }
649 }
650
Elliott Hughesb628cb12015-08-03 10:38:08 -0700651 // Close this directory and recurse.
652 dir.reset();
Josh Gaoa90563e2015-11-04 14:57:04 -0800653
654 // Add the current directory to the list if it was empty, to ensure that
655 // it gets created.
656 if (empty_dir) {
657 // TODO(b/25566053): Make pushing empty directories work.
658 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gaoa544cc62015-11-07 17:18:44 -0800659 sc.Warning("skipping empty directory '%s'", lpath.c_str());
Josh Gaod9a2fd62015-12-09 14:03:30 -0800660 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
Josh Gaoa90563e2015-11-04 14:57:04 -0800661 ci.skip = true;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800662 file_list->push_back(ci);
Josh Gaoa90563e2015-11-04 14:57:04 -0800663 return true;
664 }
665
Josh Gao204d21e2015-11-02 16:45:47 -0800666 for (const copyinfo& ci : dirlist) {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800667 local_build_list(sc, file_list, ci.lpath, ci.rpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800668 }
669
Josh Gao8efa6462015-11-03 15:26:38 -0800670 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800671}
672
Josh Gaod20cf382015-11-03 15:23:03 -0800673static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
674 std::string rpath, bool check_timestamps,
675 bool list_only) {
676 // Make sure that both directory paths end in a slash.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800677 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800678 ensure_trailing_separators(lpath, rpath);
Josh Gaod20cf382015-11-03 15:23:03 -0800679
680 // Recursively build the list of files to copy.
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800681 std::vector<copyinfo> file_list;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800682 int pushed = 0;
683 int skipped = 0;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800684 if (!local_build_list(sc, &file_list, lpath, rpath)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700685 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800686 }
687
Elliott Hughesb628cb12015-08-03 10:38:08 -0700688 if (check_timestamps) {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800689 for (const copyinfo& ci : file_list) {
Josh Gaoa3b6a062015-11-09 11:12:14 -0800690 if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
Josh Gaod20cf382015-11-03 15:23:03 -0800691 return false;
692 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800693 }
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800694 for (copyinfo& ci : file_list) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800695 unsigned int timestamp, mode, size;
Josh Gaod20cf382015-11-03 15:23:03 -0800696 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
697 return false;
698 }
Josh Gao204d21e2015-11-02 16:45:47 -0800699 if (size == ci.size) {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800700 // For links, we cannot update the atime/mtime.
Josh Gao204d21e2015-11-02 16:45:47 -0800701 if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
702 (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
Josh Gaocb094c62015-11-03 14:44:04 -0800703 ci.skip = true;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700704 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800705 }
706 }
707 }
Josh Gao204d21e2015-11-02 16:45:47 -0800708
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800709 sc.ComputeExpectedTotalBytes(file_list);
710
711 for (const copyinfo& ci : file_list) {
Josh Gaocb094c62015-11-03 14:44:04 -0800712 if (!ci.skip) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700713 if (list_only) {
Josh Gao23891f12016-08-04 14:55:23 -0700714 sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700715 } else {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800716 if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) {
Josh Gaod20cf382015-11-03 15:23:03 -0800717 return false;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700718 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800719 }
720 pushed++;
721 } else {
722 skipped++;
723 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800724 }
725
Josh Gaof35fede2016-08-04 11:43:00 -0700726 sc.Println("%s: %d file%s pushed. %d file%s skipped.%s", rpath.c_str(), pushed,
727 (pushed == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s",
728 sc.TransferRate().c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -0700729 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800730}
731
Josh Gao5d093b22015-10-30 16:57:19 -0700732bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700733 SyncConnection sc;
734 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800735
Josh Gao5d093b22015-10-30 16:57:19 -0700736 bool success = true;
Josh Gaoa5cea712015-11-07 15:27:26 -0800737 unsigned dst_mode;
738 if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false;
739 bool dst_exists = (dst_mode != 0);
Josh Gao8acf06c2015-11-07 15:38:19 -0800740 bool dst_isdir = S_ISDIR(dst_mode);
Josh Gao5d093b22015-10-30 16:57:19 -0700741
Josh Gao8acf06c2015-11-07 15:38:19 -0800742 if (!dst_isdir) {
Josh Gao5d093b22015-10-30 16:57:19 -0700743 if (srcs.size() > 1) {
744 sc.Error("target '%s' is not a directory", dst);
745 return false;
746 } else {
747 size_t dst_len = strlen(dst);
Josh Gaoa5cea712015-11-07 15:27:26 -0800748
749 // A path that ends with a slash doesn't have to be a directory if
750 // it doesn't exist yet.
751 if (dst[dst_len - 1] == '/' && dst_exists) {
Josh Gao5d093b22015-10-30 16:57:19 -0700752 sc.Error("failed to access '%s': Not a directory", dst);
753 return false;
754 }
755 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700756 }
Josh Gao5d093b22015-10-30 16:57:19 -0700757
758 for (const char* src_path : srcs) {
759 const char* dst_path = dst;
760 struct stat st;
Josh Gaoa5cea712015-11-07 15:27:26 -0800761 if (stat(src_path, &st) == -1) {
Josh Gao5d093b22015-10-30 16:57:19 -0700762 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
763 success = false;
764 continue;
765 }
766
767 if (S_ISDIR(st.st_mode)) {
Josh Gao8acf06c2015-11-07 15:38:19 -0800768 std::string dst_dir = dst;
769
770 // If the destination path existed originally, the source directory
771 // should be copied as a child of the destination.
772 if (dst_exists) {
773 if (!dst_isdir) {
774 sc.Error("target '%s' is not a directory", dst);
775 return false;
776 }
777 // dst is a POSIX path, so we don't want to use the sysdeps
778 // helpers here.
779 if (dst_dir.back() != '/') {
780 dst_dir.push_back('/');
781 }
782 dst_dir.append(adb_basename(src_path));
783 }
784
785 success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(),
786 false, false);
Josh Gao5d093b22015-10-30 16:57:19 -0700787 continue;
Josh Gaocaa52102016-03-02 16:11:13 -0800788 } else if (!should_push_file(st.st_mode)) {
789 sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
790 continue;
Josh Gao5d093b22015-10-30 16:57:19 -0700791 }
792
793 std::string path_holder;
Josh Gao8acf06c2015-11-07 15:38:19 -0800794 if (dst_isdir) {
Josh Gao5d093b22015-10-30 16:57:19 -0700795 // If we're copying a local file to a remote directory,
796 // we really want to copy to remote_dir + "/" + local_filename.
Josh Gao2e4ed0a2016-02-03 14:55:24 -0800797 path_holder = dst_path;
798 if (path_holder.back() != '/') {
799 path_holder.push_back('/');
800 }
801 path_holder += adb_basename(src_path);
Josh Gao5d093b22015-10-30 16:57:19 -0700802 dst_path = path_holder.c_str();
803 }
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800804 sc.SetExpectedTotalBytes(st.st_size);
Josh Gao5d093b22015-10-30 16:57:19 -0700805 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
806 }
807
Josh Gao5d093b22015-10-30 16:57:19 -0700808 return success;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800809}
810
Josh Gaod9a2fd62015-12-09 14:03:30 -0800811static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) {
812 unsigned mode;
813 std::string dir_path = rpath;
814 dir_path.push_back('/');
815 if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) {
816 sc.Error("failed to stat remote symlink '%s'", dir_path.c_str());
817 return false;
818 }
819 return S_ISDIR(mode);
820}
821
Josh Gao7634e882016-02-25 17:12:45 -0800822static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
823 const std::string& rpath, const std::string& lpath) {
Josh Gao204d21e2015-11-02 16:45:47 -0800824 std::vector<copyinfo> dirlist;
Josh Gaod9a2fd62015-12-09 14:03:30 -0800825 std::vector<copyinfo> linklist;
Josh Gao7634e882016-02-25 17:12:45 -0800826
827 // Add an entry for the current directory to ensure it gets created before pulling its contents.
Josh Gaoa842b382016-03-02 16:00:02 -0800828 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
Josh Gao7634e882016-02-25 17:12:45 -0800829 file_list->push_back(ci);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800830
Elliott Hughesb628cb12015-08-03 10:38:08 -0700831 // Put the files/dirs in rpath on the lists.
Josh Gaob3cab932015-11-30 10:21:25 -0800832 auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800833 if (IsDotOrDotDot(name)) {
834 return;
835 }
Josh Gao204d21e2015-11-02 16:45:47 -0800836
Josh Gaod9a2fd62015-12-09 14:03:30 -0800837 copyinfo ci(lpath, rpath, name, mode);
Josh Gaoa90563e2015-11-04 14:57:04 -0800838 if (S_ISDIR(mode)) {
839 dirlist.push_back(ci);
Josh Gaod9a2fd62015-12-09 14:03:30 -0800840 } else if (S_ISLNK(mode)) {
841 linklist.push_back(ci);
Josh Gao204d21e2015-11-02 16:45:47 -0800842 } else {
Josh Gaocaa52102016-03-02 16:11:13 -0800843 if (!should_pull_file(ci.mode)) {
844 sc.Warning("skipping special file '%s' (mode = 0o%o)", ci.rpath.c_str(), ci.mode);
845 ci.skip = true;
846 }
Josh Gaod9a2fd62015-12-09 14:03:30 -0800847 ci.time = time;
848 ci.size = size;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800849 file_list->push_back(ci);
Josh Gao204d21e2015-11-02 16:45:47 -0800850 }
851 };
852
Josh Gaod20cf382015-11-03 15:23:03 -0800853 if (!sync_ls(sc, rpath.c_str(), callback)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700854 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800855 }
856
Josh Gaod9a2fd62015-12-09 14:03:30 -0800857 // Check each symlink we found to see whether it's a file or directory.
858 for (copyinfo& link_ci : linklist) {
859 if (remote_symlink_isdir(sc, link_ci.rpath)) {
860 dirlist.emplace_back(std::move(link_ci));
861 } else {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800862 file_list->emplace_back(std::move(link_ci));
Josh Gaod9a2fd62015-12-09 14:03:30 -0800863 }
864 }
865
Elliott Hughesb628cb12015-08-03 10:38:08 -0700866 // Recurse into each directory we found.
Josh Gao204d21e2015-11-02 16:45:47 -0800867 while (!dirlist.empty()) {
868 copyinfo current = dirlist.back();
869 dirlist.pop_back();
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800870 if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700871 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800872 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800873 }
874
Elliott Hughesb628cb12015-08-03 10:38:08 -0700875 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800876}
877
Josh Gaoa3b6a062015-11-09 11:12:14 -0800878static int set_time_and_mode(const std::string& lpath, time_t time,
879 unsigned int mode) {
Greg Hackmann8b689142014-05-06 08:48:18 -0700880 struct utimbuf times = { time, time };
Josh Gaoa3b6a062015-11-09 11:12:14 -0800881 int r1 = utime(lpath.c_str(), &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700882
883 /* use umask for permissions */
Josh Gao204d21e2015-11-02 16:45:47 -0800884 mode_t mask = umask(0000);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700885 umask(mask);
Josh Gaoa3b6a062015-11-09 11:12:14 -0800886 int r2 = chmod(lpath.c_str(), mode & ~mask);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700887
Spencer Low28bc2cb2015-11-07 18:51:54 -0800888 return r1 ? r1 : r2;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700889}
890
Josh Gaod20cf382015-11-03 15:23:03 -0800891static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
892 std::string lpath, bool copy_attrs) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700893 // Make sure that both directory paths end in a slash.
Josh Gaoa5cea712015-11-07 15:27:26 -0800894 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800895 ensure_trailing_separators(lpath, rpath);
Riley Andrewsc736a942014-12-12 13:12:36 -0800896
Elliott Hughesb628cb12015-08-03 10:38:08 -0700897 // Recursively build the list of files to copy.
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800898 sc.Printf("pull: building file list...");
899 std::vector<copyinfo> file_list;
900 if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
Josh Gao204d21e2015-11-02 16:45:47 -0800901 return false;
902 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700903
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800904 sc.ComputeExpectedTotalBytes(file_list);
905
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800906 int pulled = 0;
907 int skipped = 0;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800908 for (const copyinfo &ci : file_list) {
Josh Gaocb094c62015-11-03 14:44:04 -0800909 if (!ci.skip) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800910 if (S_ISDIR(ci.mode)) {
911 // Entry is for an empty directory, create it and continue.
912 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800913 if (!mkdirs(ci.lpath)) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800914 sc.Error("failed to create directory '%s': %s",
Josh Gaoa3b6a062015-11-09 11:12:14 -0800915 ci.lpath.c_str(), strerror(errno));
Josh Gaoa90563e2015-11-04 14:57:04 -0800916 return false;
917 }
918 pulled++;
919 continue;
920 }
921
Josh Gaoa3b6a062015-11-09 11:12:14 -0800922 if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700923 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800924 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700925
Josh Gaoa3b6a062015-11-09 11:12:14 -0800926 if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700927 return false;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700928 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800929 pulled++;
930 } else {
931 skipped++;
932 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800933 }
934
Josh Gaof35fede2016-08-04 11:43:00 -0700935 sc.Println("%s: %d file%s pulled. %d file%s skipped.%s", rpath.c_str(), pulled,
936 (pulled == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s",
937 sc.TransferRate().c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -0700938 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800939}
940
Josh Gao5d093b22015-10-30 16:57:19 -0700941bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
942 bool copy_attrs) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700943 SyncConnection sc;
944 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800945
Josh Gao5d093b22015-10-30 16:57:19 -0700946 bool success = true;
Josh Gao5d093b22015-10-30 16:57:19 -0700947 struct stat st;
Josh Gaoa5cea712015-11-07 15:27:26 -0800948 bool dst_exists = true;
949
950 if (stat(dst, &st) == -1) {
951 dst_exists = false;
952
953 // If we're only pulling one path, the destination path might point to
Josh Gao5d093b22015-10-30 16:57:19 -0700954 // a path that doesn't exist yet.
Josh Gaoa5cea712015-11-07 15:27:26 -0800955 if (srcs.size() == 1 && errno == ENOENT) {
956 // However, its parent must exist.
957 struct stat parent_st;
958 if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
959 sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
960 return false;
961 }
962 } else {
963 sc.Error("failed to access '%s': %s", dst, strerror(errno));
Josh Gao5d093b22015-10-30 16:57:19 -0700964 return false;
965 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800966 }
967
Josh Gao8acf06c2015-11-07 15:38:19 -0800968 bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
969 if (!dst_isdir) {
Josh Gao5d093b22015-10-30 16:57:19 -0700970 if (srcs.size() > 1) {
971 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700972 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800973 } else {
Josh Gao5d093b22015-10-30 16:57:19 -0700974 size_t dst_len = strlen(dst);
Josh Gaoa5cea712015-11-07 15:27:26 -0800975
976 // A path that ends with a slash doesn't have to be a directory if
977 // it doesn't exist yet.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800978 if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
Josh Gao5d093b22015-10-30 16:57:19 -0700979 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700980 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700981 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800982 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800983 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700984
Josh Gao5d093b22015-10-30 16:57:19 -0700985 for (const char* src_path : srcs) {
986 const char* dst_path = dst;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800987 unsigned src_mode, src_time, src_size;
988 if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) {
Josh Gaod9a2fd62015-12-09 14:03:30 -0800989 sc.Error("failed to stat remote object '%s'", src_path);
Josh Gaoa5cea712015-11-07 15:27:26 -0800990 return false;
991 }
992 if (src_mode == 0) {
Josh Gao5d093b22015-10-30 16:57:19 -0700993 sc.Error("remote object '%s' does not exist", src_path);
994 success = false;
995 continue;
996 }
997
Josh Gaod9a2fd62015-12-09 14:03:30 -0800998 bool src_isdir = S_ISDIR(src_mode);
999 if (S_ISLNK(src_mode)) {
1000 src_isdir = remote_symlink_isdir(sc, src_path);
1001 }
1002
Josh Gaod9a2fd62015-12-09 14:03:30 -08001003 if (src_isdir) {
Josh Gao8acf06c2015-11-07 15:38:19 -08001004 std::string dst_dir = dst;
1005
1006 // If the destination path existed originally, the source directory
1007 // should be copied as a child of the destination.
1008 if (dst_exists) {
1009 if (!dst_isdir) {
1010 sc.Error("target '%s' is not a directory", dst);
1011 return false;
1012 }
1013 if (!adb_is_separator(dst_dir.back())) {
1014 dst_dir.push_back(OS_PATH_SEPARATOR);
1015 }
1016 dst_dir.append(adb_basename(src_path));
1017 }
1018
Josh Gaod9a2fd62015-12-09 14:03:30 -08001019 success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
Josh Gao5d093b22015-10-30 16:57:19 -07001020 continue;
Josh Gaocaa52102016-03-02 16:11:13 -08001021 } else if (!should_pull_file(src_mode)) {
1022 sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_mode);
1023 continue;
1024 }
Josh Gaod9a2fd62015-12-09 14:03:30 -08001025
Josh Gaocaa52102016-03-02 16:11:13 -08001026 std::string path_holder;
1027 if (dst_isdir) {
1028 // If we're copying a remote file to a local directory, we
1029 // really want to copy to local_dir + OS_PATH_SEPARATOR +
1030 // basename(remote).
1031 path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
1032 adb_basename(src_path).c_str());
1033 dst_path = path_holder.c_str();
1034 }
Josh Gaod9a2fd62015-12-09 14:03:30 -08001035
Josh Gaocaa52102016-03-02 16:11:13 -08001036 sc.SetExpectedTotalBytes(src_size);
1037 if (!sync_recv(sc, src_path, dst_path)) {
1038 success = false;
1039 continue;
1040 }
1041
1042 if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) {
1043 success = false;
1044 continue;
Josh Gao5d093b22015-10-30 16:57:19 -07001045 }
1046 }
1047
Josh Gao5d093b22015-10-30 16:57:19 -07001048 return success;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001049}
1050
Elliott Hughesb628cb12015-08-03 10:38:08 -07001051bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesb628cb12015-08-03 10:38:08 -07001052 SyncConnection sc;
1053 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001054
Josh Gaod20cf382015-11-03 15:23:03 -08001055 return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001056}