blob: 3a81ce6acaac0fd0feb3ac1cfe23fa7d0f1e5b6c [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
63struct copyinfo {
64 std::string lpath;
65 std::string rpath;
66 unsigned int time = 0;
67 unsigned int mode;
68 uint64_t size = 0;
69 bool skip = false;
70
71 copyinfo(const std::string& local_path,
72 const std::string& remote_path,
73 const std::string& name,
74 unsigned int mode)
75 : lpath(local_path), rpath(remote_path), mode(mode) {
76 ensure_trailing_separators(lpath, rpath);
77 lpath.append(name);
78 rpath.append(name);
79 if (S_ISDIR(mode)) {
80 ensure_trailing_separators(lpath, rpath);
81 }
82 }
83};
84
Elliott Hughesb628cb12015-08-03 10:38:08 -070085class SyncConnection {
86 public:
Elliott Hughes7b43fa52015-12-17 17:05:29 -080087 SyncConnection()
88 : total_bytes_(0),
89 start_time_ms_(CurrentTimeMs()),
90 expected_total_bytes_(0),
Josh Gaoa53abe72016-02-19 15:55:55 -080091 expect_multiple_files_(false),
92 expect_done_(false) {
Elliott Hughesb628cb12015-08-03 10:38:08 -070093 max = SYNC_DATA_MAX; // TODO: decide at runtime.
94
95 std::string error;
96 fd = adb_connect("sync:", &error);
97 if (fd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070098 Error("connect failed: %s", error.c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -070099 }
100 }
101
102 ~SyncConnection() {
103 if (!IsValid()) return;
104
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700105 if (SendQuit()) {
106 // We sent a quit command, so the server should be doing orderly
107 // shutdown soon. But if we encountered an error while we were using
108 // the connection, the server might still be sending data (before
109 // doing orderly shutdown), in which case we won't wait for all of
110 // the data nor the coming orderly shutdown. In the common success
111 // case, this will wait for the server to do orderly shutdown.
112 ReadOrderlyShutdown(fd);
113 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700114 adb_close(fd);
Elliott Hughes78a37a52015-12-08 16:01:15 -0800115
116 line_printer_.KeepInfoLine();
Elliott Hughesb628cb12015-08-03 10:38:08 -0700117 }
118
119 bool IsValid() { return fd >= 0; }
120
Josh Gaoa53abe72016-02-19 15:55:55 -0800121 bool ReceivedError(const char* from, const char* to) {
122 adb_pollfd pfd = {.fd = fd, .events = POLLIN};
123 int rc = adb_poll(&pfd, 1, 0);
124 if (rc < 0) {
125 Error("failed to poll: %s", strerror(errno));
126 return true;
127 }
128 return rc != 0;
129 }
130
Elliott Hughesdde00be2015-09-27 12:55:37 -0700131 bool SendRequest(int id, const char* path_and_mode) {
132 size_t path_length = strlen(path_and_mode);
133 if (path_length > 1024) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700134 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700135 errno = ENAMETOOLONG;
136 return false;
137 }
138
139 // Sending header and payload in a single write makes a noticeable
140 // difference to "adb sync" performance.
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700141 std::vector<char> buf(sizeof(SyncRequest) + path_length);
142 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700143 req->id = id;
144 req->path_length = path_length;
145 char* data = reinterpret_cast<char*>(req + 1);
146 memcpy(data, path_and_mode, path_length);
147
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700148 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesdde00be2015-09-27 12:55:37 -0700149 }
150
151 // Sending header, payload, and footer in a single write makes a huge
152 // difference to "adb sync" performance.
153 bool SendSmallFile(const char* path_and_mode,
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800154 const char* lpath, const char* rpath,
Elliott Hughes7275d802015-11-20 17:35:17 -0800155 unsigned mtime,
156 const char* data, size_t data_length) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700157 size_t path_length = strlen(path_and_mode);
158 if (path_length > 1024) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700159 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700160 errno = ENAMETOOLONG;
161 return false;
162 }
163
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700164 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughes7275d802015-11-20 17:35:17 -0800165 sizeof(SyncRequest) + data_length +
166 sizeof(SyncRequest));
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700167 char* p = &buf[0];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700168
169 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
170 req_send->id = ID_SEND;
171 req_send->path_length = path_length;
172 p += sizeof(SyncRequest);
173 memcpy(p, path_and_mode, path_length);
174 p += path_length;
175
176 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
177 req_data->id = ID_DATA;
178 req_data->path_length = data_length;
179 p += sizeof(SyncRequest);
180 memcpy(p, data, data_length);
181 p += data_length;
182
183 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
184 req_done->id = ID_DONE;
185 req_done->path_length = mtime;
186 p += sizeof(SyncRequest);
187
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800188 WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
Josh Gaoa53abe72016-02-19 15:55:55 -0800189 expect_done_ = true;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800190 total_bytes_ += data_length;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700191 return true;
192 }
193
Elliott Hughes7275d802015-11-20 17:35:17 -0800194 bool SendLargeFile(const char* path_and_mode,
195 const char* lpath, const char* rpath,
196 unsigned mtime) {
197 if (!SendRequest(ID_SEND, path_and_mode)) {
198 Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
199 return false;
200 }
201
202 struct stat st;
203 if (stat(lpath, &st) == -1) {
204 Error("cannot stat '%s': %s", lpath, strerror(errno));
205 return false;
206 }
207
208 uint64_t total_size = st.st_size;
209 uint64_t bytes_copied = 0;
210
211 int lfd = adb_open(lpath, O_RDONLY);
212 if (lfd < 0) {
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800213 Error("opening '%s' locally failed: %s", lpath, strerror(errno));
Elliott Hughes7275d802015-11-20 17:35:17 -0800214 return false;
215 }
216
217 syncsendbuf sbuf;
218 sbuf.id = ID_DATA;
219 while (true) {
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800220 int bytes_read = adb_read(lfd, sbuf.data, max);
221 if (bytes_read == -1) {
222 Error("reading '%s' locally failed: %s", lpath, strerror(errno));
223 adb_close(lfd);
224 return false;
225 } else if (bytes_read == 0) {
Elliott Hughes7275d802015-11-20 17:35:17 -0800226 break;
227 }
228
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800229 sbuf.size = bytes_read;
230 WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
Elliott Hughes7275d802015-11-20 17:35:17 -0800231
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800232 total_bytes_ += bytes_read;
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800233 bytes_copied += bytes_read;
Elliott Hughes7275d802015-11-20 17:35:17 -0800234
Josh Gaoa53abe72016-02-19 15:55:55 -0800235 // Check to see if we've received an error from the other side.
236 if (ReceivedError(lpath, rpath)) {
237 break;
238 }
239
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800240 ReportProgress(rpath, bytes_copied, total_size);
Elliott Hughes7275d802015-11-20 17:35:17 -0800241 }
242
243 adb_close(lfd);
244
245 syncmsg msg;
246 msg.data.id = ID_DONE;
247 msg.data.size = mtime;
Josh Gaoa53abe72016-02-19 15:55:55 -0800248 expect_done_ = true;
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800249 return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
Elliott Hughes7275d802015-11-20 17:35:17 -0800250 }
251
Elliott Hughesdde00be2015-09-27 12:55:37 -0700252 bool CopyDone(const char* from, const char* to) {
253 syncmsg msg;
254 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Josh Gaoa53abe72016-02-19 15:55:55 -0800255 Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700256 return false;
257 }
258 if (msg.status.id == ID_OKAY) {
Josh Gaoa53abe72016-02-19 15:55:55 -0800259 if (expect_done_) {
260 expect_done_ = false;
261 return true;
262 } else {
263 Error("failed to copy '%s' to '%s': received premature success", from, to);
264 return true;
265 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700266 }
267 if (msg.status.id != ID_FAIL) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700268 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700269 return false;
270 }
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700271 return ReportCopyFailure(from, to, msg);
272 }
273
274 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700275 std::vector<char> buf(msg.status.msglen + 1);
276 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700277 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
278 from, to, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700279 return false;
280 }
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700281 buf[msg.status.msglen] = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700282 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700283 return false;
284 }
285
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700286 std::string TransferRate() {
287 uint64_t ms = CurrentTimeMs() - start_time_ms_;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800288 if (total_bytes_ == 0 || ms == 0) return "";
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700289
290 double s = static_cast<double>(ms) / 1000LL;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800291 double rate = (static_cast<double>(total_bytes_) / s) / (1024*1024);
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700292 return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800293 rate, total_bytes_, s);
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700294 }
295
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800296 void ReportProgress(const char* file, uint64_t file_copied_bytes, uint64_t file_total_bytes) {
297 char overall_percentage_str[5] = "?";
298 if (expected_total_bytes_ != 0) {
299 int overall_percentage = static_cast<int>(total_bytes_ * 100 / expected_total_bytes_);
300 // If we're pulling symbolic links, we'll pull the target of the link rather than
301 // just create a local link, and that will cause us to go over 100%.
302 if (overall_percentage <= 100) {
303 snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
304 overall_percentage);
305 }
306 }
307
308 if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
309 // This case can happen if we're racing against something that wrote to the file
310 // between our stat and our read, or if we're reading a magic file that lies about
311 // its size. Just show how much we've copied.
312 Printf("[%4s] %s: %" PRId64 "/?", overall_percentage_str, file, file_copied_bytes);
313 } else {
314 // If we're transferring multiple files, we want to know how far through the current
315 // file we are, as well as the overall percentage.
316 if (expect_multiple_files_) {
317 int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
318 Printf("[%4s] %s: %d%%", overall_percentage_str, file, file_percentage);
319 } else {
320 Printf("[%4s] %s", overall_percentage_str, file);
321 }
322 }
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700323 }
324
Josh Gaocbf485f2015-11-02 17:15:57 -0800325 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
326 std::string s;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800327
Josh Gaocbf485f2015-11-02 17:15:57 -0800328 va_list ap;
329 va_start(ap, fmt);
330 android::base::StringAppendV(&s, fmt, ap);
331 va_end(ap);
332
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800333 line_printer_.Print(s, LinePrinter::INFO);
Josh Gaocbf485f2015-11-02 17:15:57 -0800334 }
335
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700336 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
337 std::string s = "adb: error: ";
338
339 va_list ap;
340 va_start(ap, fmt);
341 android::base::StringAppendV(&s, fmt, ap);
342 va_end(ap);
343
Elliott Hughes78a37a52015-12-08 16:01:15 -0800344 line_printer_.Print(s, LinePrinter::ERROR);
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700345 }
346
Josh Gaoa544cc62015-11-07 17:18:44 -0800347 void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
348 std::string s = "adb: warning: ";
349
350 va_list ap;
351 va_start(ap, fmt);
352 android::base::StringAppendV(&s, fmt, ap);
353 va_end(ap);
354
Elliott Hughes78a37a52015-12-08 16:01:15 -0800355 line_printer_.Print(s, LinePrinter::WARNING);
Josh Gaoa544cc62015-11-07 17:18:44 -0800356 }
357
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800358 void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
359 expected_total_bytes_ = 0;
360 for (const copyinfo& ci : file_list) {
361 // Unfortunately, this doesn't work for symbolic links, because we'll copy the
362 // target of the link rather than just creating a link. (But ci.size is the link size.)
363 if (!ci.skip) expected_total_bytes_ += ci.size;
364 }
365 expect_multiple_files_ = true;
366 }
367
368 void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
369 expected_total_bytes_ = expected_total_bytes;
370 expect_multiple_files_ = false;
371 }
372
373 uint64_t total_bytes_;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700374
375 // TODO: add a char[max] buffer here, to replace syncsendbuf...
376 int fd;
377 size_t max;
378
379 private:
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700380 uint64_t start_time_ms_;
381
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800382 uint64_t expected_total_bytes_;
383 bool expect_multiple_files_;
Josh Gaoa53abe72016-02-19 15:55:55 -0800384 bool expect_done_;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800385
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700386 LinePrinter line_printer_;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700387
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700388 bool SendQuit() {
389 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesb628cb12015-08-03 10:38:08 -0700390 }
391
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800392 bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
393 if (!WriteFdExactly(fd, data, data_length)) {
394 if (errno == ECONNRESET) {
395 // Assume adbd told us why it was closing the connection, and
396 // try to read failure reason from adbd.
397 syncmsg msg;
398 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
399 Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
400 } else if (msg.status.id != ID_FAIL) {
401 Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
402 } else {
403 ReportCopyFailure(from, to, msg);
404 }
405 } else {
406 Error("%zu-byte write failed: %s", data_length, strerror(errno));
407 }
408 _exit(1);
409 }
410 return true;
411 }
412
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700413 static uint64_t CurrentTimeMs() {
414 struct timeval tv;
415 gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
416 return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700417 }
418};
419
Josh Gao204d21e2015-11-02 16:45:47 -0800420typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700421
Josh Gao204d21e2015-11-02 16:45:47 -0800422static bool sync_ls(SyncConnection& sc, const char* path,
423 std::function<sync_ls_cb> func) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700424 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700425
426 while (true) {
427 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700428 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700429
430 if (msg.dent.id == ID_DONE) return true;
431 if (msg.dent.id != ID_DENT) return false;
432
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700433 size_t len = msg.dent.namelen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700434 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800435
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700436 char buf[257];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700437 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800438 buf[len] = 0;
439
Josh Gao204d21e2015-11-02 16:45:47 -0800440 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800441 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800442}
443
Elliott Hughesb628cb12015-08-03 10:38:08 -0700444static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
445 unsigned int* mode, unsigned int* size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800446 syncmsg msg;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700447 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
448 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800449 }
450
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700451 if (timestamp) *timestamp = msg.stat.time;
452 if (mode) *mode = msg.stat.mode;
453 if (size) *size = msg.stat.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800454
Elliott Hughesb628cb12015-08-03 10:38:08 -0700455 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800456}
457
Elliott Hughesb628cb12015-08-03 10:38:08 -0700458static bool sync_stat(SyncConnection& sc, const char* path,
459 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700460 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800461}
462
Elliott Hughesdde00be2015-09-27 12:55:37 -0700463static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700464 unsigned mtime, mode_t mode)
Elliott Hughesdde00be2015-09-27 12:55:37 -0700465{
466 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
467
468 if (S_ISLNK(mode)) {
469#if !defined(_WIN32)
470 char buf[PATH_MAX];
471 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
472 if (data_length == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700473 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700474 return false;
475 }
476 buf[data_length++] = '\0';
477
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800478 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
479 return false;
480 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700481 return sc.CopyDone(lpath, rpath);
482#endif
483 }
484
485 if (!S_ISREG(mode)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700486 sc.Error("local file '%s' has unsupported mode: 0o%o", lpath, mode);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700487 return false;
488 }
489
490 struct stat st;
491 if (stat(lpath, &st) == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700492 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700493 return false;
494 }
495 if (st.st_size < SYNC_DATA_MAX) {
496 std::string data;
497 if (!android::base::ReadFileToString(lpath, &data)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700498 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700499 return false;
500 }
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800501 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
502 data.data(), data.size())) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700503 return false;
504 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700505 } else {
Elliott Hughes7275d802015-11-20 17:35:17 -0800506 if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700507 return false;
508 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700509 }
510 return sc.CopyDone(lpath, rpath);
511}
512
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700513static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700514 unsigned size = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700515 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700516
Elliott Hughesdde00be2015-09-27 12:55:37 -0700517 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800518
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700519 adb_unlink(lpath);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700520 int lfd = adb_creat(lpath, 0644);
521 if (lfd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700522 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700523 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800524 }
525
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700526 uint64_t bytes_copied = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700527 while (true) {
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700528 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700529 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700530 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700531 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700532 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800533 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800534
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700535 if (msg.data.id == ID_DONE) break;
536
537 if (msg.data.id != ID_DATA) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800538 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700539 adb_unlink(lpath);
540 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700541 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800542 }
543
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700544 if (msg.data.size > sc.max) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700545 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 -0800546 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700547 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700548 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800549 }
550
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700551 char buffer[SYNC_DATA_MAX];
552 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800553 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700554 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700555 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800556 }
557
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700558 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700559 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700560 adb_close(lfd);
561 adb_unlink(lpath);
562 return false;
563 }
564
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800565 sc.total_bytes_ += msg.data.size;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700566
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700567 bytes_copied += msg.data.size;
568
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800569 sc.ReportProgress(rpath, bytes_copied, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800570 }
571
572 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700573 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800574}
575
Elliott Hughesb628cb12015-08-03 10:38:08 -0700576bool do_sync_ls(const char* path) {
577 SyncConnection sc;
578 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800579
Josh Gao204d21e2015-11-02 16:45:47 -0800580 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
581 const char* name) {
582 printf("%08x %08x %08x %s\n", mode, size, time, name);
583 });
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800584}
585
Elliott Hughesb628cb12015-08-03 10:38:08 -0700586static bool IsDotOrDotDot(const char* name) {
587 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
588}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800589
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800590static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
Josh Gao8efa6462015-11-03 15:26:38 -0800591 const std::string& lpath,
592 const std::string& rpath) {
Josh Gao204d21e2015-11-02 16:45:47 -0800593 std::vector<copyinfo> dirlist;
Josh Gaod20cf382015-11-03 15:23:03 -0800594 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700595 if (!dir) {
Josh Gaod20cf382015-11-03 15:23:03 -0800596 sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
Josh Gao8efa6462015-11-03 15:26:38 -0800597 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800598 }
599
Josh Gaoa90563e2015-11-04 14:57:04 -0800600 bool empty_dir = true;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700601 dirent* de;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700602 while ((de = readdir(dir.get()))) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800603 if (IsDotOrDotDot(de->d_name)) {
604 continue;
605 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700606
Josh Gaoa90563e2015-11-04 14:57:04 -0800607 empty_dir = false;
Josh Gaod20cf382015-11-03 15:23:03 -0800608 std::string stat_path = lpath + de->d_name;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800609
Elliott Hughesb628cb12015-08-03 10:38:08 -0700610 struct stat st;
Josh Gaoa5cea712015-11-07 15:27:26 -0800611 if (lstat(stat_path.c_str(), &st) == -1) {
Josh Gaod20cf382015-11-03 15:23:03 -0800612 sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
613 strerror(errno));
Josh Gaoa5cea712015-11-07 15:27:26 -0800614 continue;
615 }
616
Josh Gaod9a2fd62015-12-09 14:03:30 -0800617 copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
Josh Gaoa5cea712015-11-07 15:27:26 -0800618 if (S_ISDIR(st.st_mode)) {
619 dirlist.push_back(ci);
620 } else {
621 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
622 sc.Error("skipping special file '%s'", lpath.c_str());
Josh Gaob3cab932015-11-30 10:21:25 -0800623 ci.skip = true;
Josh Gaoa5cea712015-11-07 15:27:26 -0800624 } else {
625 ci.time = st.st_mtime;
626 ci.size = st.st_size;
Josh Gaoa5cea712015-11-07 15:27:26 -0800627 }
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800628 file_list->push_back(ci);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800629 }
630 }
631
Elliott Hughesb628cb12015-08-03 10:38:08 -0700632 // Close this directory and recurse.
633 dir.reset();
Josh Gaoa90563e2015-11-04 14:57:04 -0800634
635 // Add the current directory to the list if it was empty, to ensure that
636 // it gets created.
637 if (empty_dir) {
638 // TODO(b/25566053): Make pushing empty directories work.
639 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gaoa544cc62015-11-07 17:18:44 -0800640 sc.Warning("skipping empty directory '%s'", lpath.c_str());
Josh Gaod9a2fd62015-12-09 14:03:30 -0800641 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
Josh Gaoa90563e2015-11-04 14:57:04 -0800642 ci.skip = true;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800643 file_list->push_back(ci);
Josh Gaoa90563e2015-11-04 14:57:04 -0800644 return true;
645 }
646
Josh Gao204d21e2015-11-02 16:45:47 -0800647 for (const copyinfo& ci : dirlist) {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800648 local_build_list(sc, file_list, ci.lpath, ci.rpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800649 }
650
Josh Gao8efa6462015-11-03 15:26:38 -0800651 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800652}
653
Josh Gaod20cf382015-11-03 15:23:03 -0800654static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
655 std::string rpath, bool check_timestamps,
656 bool list_only) {
657 // Make sure that both directory paths end in a slash.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800658 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800659 ensure_trailing_separators(lpath, rpath);
Josh Gaod20cf382015-11-03 15:23:03 -0800660
661 // Recursively build the list of files to copy.
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800662 std::vector<copyinfo> file_list;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800663 int pushed = 0;
664 int skipped = 0;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800665 if (!local_build_list(sc, &file_list, lpath, rpath)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700666 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800667 }
668
Elliott Hughesb628cb12015-08-03 10:38:08 -0700669 if (check_timestamps) {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800670 for (const copyinfo& ci : file_list) {
Josh Gaoa3b6a062015-11-09 11:12:14 -0800671 if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
Josh Gaod20cf382015-11-03 15:23:03 -0800672 return false;
673 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800674 }
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800675 for (copyinfo& ci : file_list) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800676 unsigned int timestamp, mode, size;
Josh Gaod20cf382015-11-03 15:23:03 -0800677 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
678 return false;
679 }
Josh Gao204d21e2015-11-02 16:45:47 -0800680 if (size == ci.size) {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800681 // For links, we cannot update the atime/mtime.
Josh Gao204d21e2015-11-02 16:45:47 -0800682 if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
683 (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
Josh Gaocb094c62015-11-03 14:44:04 -0800684 ci.skip = true;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700685 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800686 }
687 }
688 }
Josh Gao204d21e2015-11-02 16:45:47 -0800689
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800690 sc.ComputeExpectedTotalBytes(file_list);
691
692 for (const copyinfo& ci : file_list) {
Josh Gaocb094c62015-11-03 14:44:04 -0800693 if (!ci.skip) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700694 if (list_only) {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800695 sc.Error("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700696 } else {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800697 if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) {
Josh Gaod20cf382015-11-03 15:23:03 -0800698 return false;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700699 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800700 }
701 pushed++;
702 } else {
703 skipped++;
704 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800705 }
706
Elliott Hughes78a37a52015-12-08 16:01:15 -0800707 sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s", rpath.c_str(),
Josh Gaod20cf382015-11-03 15:23:03 -0800708 pushed, (pushed == 1) ? "" : "s", skipped,
709 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -0700710 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800711}
712
Josh Gao5d093b22015-10-30 16:57:19 -0700713bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700714 SyncConnection sc;
715 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800716
Josh Gao5d093b22015-10-30 16:57:19 -0700717 bool success = true;
Josh Gaoa5cea712015-11-07 15:27:26 -0800718 unsigned dst_mode;
719 if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false;
720 bool dst_exists = (dst_mode != 0);
Josh Gao8acf06c2015-11-07 15:38:19 -0800721 bool dst_isdir = S_ISDIR(dst_mode);
Josh Gao5d093b22015-10-30 16:57:19 -0700722
Josh Gao8acf06c2015-11-07 15:38:19 -0800723 if (!dst_isdir) {
Josh Gao5d093b22015-10-30 16:57:19 -0700724 if (srcs.size() > 1) {
725 sc.Error("target '%s' is not a directory", dst);
726 return false;
727 } else {
728 size_t dst_len = strlen(dst);
Josh Gaoa5cea712015-11-07 15:27:26 -0800729
730 // A path that ends with a slash doesn't have to be a directory if
731 // it doesn't exist yet.
732 if (dst[dst_len - 1] == '/' && dst_exists) {
Josh Gao5d093b22015-10-30 16:57:19 -0700733 sc.Error("failed to access '%s': Not a directory", dst);
734 return false;
735 }
736 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700737 }
Josh Gao5d093b22015-10-30 16:57:19 -0700738
739 for (const char* src_path : srcs) {
740 const char* dst_path = dst;
741 struct stat st;
Josh Gaoa5cea712015-11-07 15:27:26 -0800742 if (stat(src_path, &st) == -1) {
Josh Gao5d093b22015-10-30 16:57:19 -0700743 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
744 success = false;
745 continue;
746 }
747
748 if (S_ISDIR(st.st_mode)) {
Josh Gao8acf06c2015-11-07 15:38:19 -0800749 std::string dst_dir = dst;
750
751 // If the destination path existed originally, the source directory
752 // should be copied as a child of the destination.
753 if (dst_exists) {
754 if (!dst_isdir) {
755 sc.Error("target '%s' is not a directory", dst);
756 return false;
757 }
758 // dst is a POSIX path, so we don't want to use the sysdeps
759 // helpers here.
760 if (dst_dir.back() != '/') {
761 dst_dir.push_back('/');
762 }
763 dst_dir.append(adb_basename(src_path));
764 }
765
766 success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(),
767 false, false);
Josh Gao5d093b22015-10-30 16:57:19 -0700768 continue;
769 }
770
771 std::string path_holder;
Josh Gao8acf06c2015-11-07 15:38:19 -0800772 if (dst_isdir) {
Josh Gao5d093b22015-10-30 16:57:19 -0700773 // If we're copying a local file to a remote directory,
774 // we really want to copy to remote_dir + "/" + local_filename.
Josh Gao2e4ed0a2016-02-03 14:55:24 -0800775 path_holder = dst_path;
776 if (path_holder.back() != '/') {
777 path_holder.push_back('/');
778 }
779 path_holder += adb_basename(src_path);
Josh Gao5d093b22015-10-30 16:57:19 -0700780 dst_path = path_holder.c_str();
781 }
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800782 sc.SetExpectedTotalBytes(st.st_size);
Josh Gao5d093b22015-10-30 16:57:19 -0700783 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
784 }
785
Josh Gao5d093b22015-10-30 16:57:19 -0700786 return success;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800787}
788
Josh Gaod9a2fd62015-12-09 14:03:30 -0800789static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) {
790 unsigned mode;
791 std::string dir_path = rpath;
792 dir_path.push_back('/');
793 if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) {
794 sc.Error("failed to stat remote symlink '%s'", dir_path.c_str());
795 return false;
796 }
797 return S_ISDIR(mode);
798}
799
Josh Gao7634e882016-02-25 17:12:45 -0800800static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
801 const std::string& rpath, const std::string& lpath) {
Josh Gao204d21e2015-11-02 16:45:47 -0800802 std::vector<copyinfo> dirlist;
Josh Gaod9a2fd62015-12-09 14:03:30 -0800803 std::vector<copyinfo> linklist;
Josh Gao7634e882016-02-25 17:12:45 -0800804
805 // Add an entry for the current directory to ensure it gets created before pulling its contents.
806 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(rpath), S_IFDIR);
807 file_list->push_back(ci);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800808
Elliott Hughesb628cb12015-08-03 10:38:08 -0700809 // Put the files/dirs in rpath on the lists.
Josh Gaob3cab932015-11-30 10:21:25 -0800810 auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800811 if (IsDotOrDotDot(name)) {
812 return;
813 }
Josh Gao204d21e2015-11-02 16:45:47 -0800814
Josh Gaod9a2fd62015-12-09 14:03:30 -0800815 copyinfo ci(lpath, rpath, name, mode);
Josh Gaoa90563e2015-11-04 14:57:04 -0800816 if (S_ISDIR(mode)) {
817 dirlist.push_back(ci);
Josh Gaod9a2fd62015-12-09 14:03:30 -0800818 } else if (S_ISLNK(mode)) {
819 linklist.push_back(ci);
Josh Gao204d21e2015-11-02 16:45:47 -0800820 } else {
Josh Gaod9a2fd62015-12-09 14:03:30 -0800821 ci.time = time;
822 ci.size = size;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800823 file_list->push_back(ci);
Josh Gao204d21e2015-11-02 16:45:47 -0800824 }
825 };
826
Josh Gaod20cf382015-11-03 15:23:03 -0800827 if (!sync_ls(sc, rpath.c_str(), callback)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700828 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800829 }
830
Josh Gaod9a2fd62015-12-09 14:03:30 -0800831 // Check each symlink we found to see whether it's a file or directory.
832 for (copyinfo& link_ci : linklist) {
833 if (remote_symlink_isdir(sc, link_ci.rpath)) {
834 dirlist.emplace_back(std::move(link_ci));
835 } else {
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800836 file_list->emplace_back(std::move(link_ci));
Josh Gaod9a2fd62015-12-09 14:03:30 -0800837 }
838 }
839
Elliott Hughesb628cb12015-08-03 10:38:08 -0700840 // Recurse into each directory we found.
Josh Gao204d21e2015-11-02 16:45:47 -0800841 while (!dirlist.empty()) {
842 copyinfo current = dirlist.back();
843 dirlist.pop_back();
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800844 if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700845 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800846 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800847 }
848
Elliott Hughesb628cb12015-08-03 10:38:08 -0700849 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800850}
851
Josh Gaoa3b6a062015-11-09 11:12:14 -0800852static int set_time_and_mode(const std::string& lpath, time_t time,
853 unsigned int mode) {
Greg Hackmann8b689142014-05-06 08:48:18 -0700854 struct utimbuf times = { time, time };
Josh Gaoa3b6a062015-11-09 11:12:14 -0800855 int r1 = utime(lpath.c_str(), &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700856
857 /* use umask for permissions */
Josh Gao204d21e2015-11-02 16:45:47 -0800858 mode_t mask = umask(0000);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700859 umask(mask);
Josh Gaoa3b6a062015-11-09 11:12:14 -0800860 int r2 = chmod(lpath.c_str(), mode & ~mask);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700861
Spencer Low28bc2cb2015-11-07 18:51:54 -0800862 return r1 ? r1 : r2;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700863}
864
Josh Gaod20cf382015-11-03 15:23:03 -0800865static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
866 std::string lpath, bool copy_attrs) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700867 // Make sure that both directory paths end in a slash.
Josh Gaoa5cea712015-11-07 15:27:26 -0800868 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800869 ensure_trailing_separators(lpath, rpath);
Riley Andrewsc736a942014-12-12 13:12:36 -0800870
Elliott Hughesb628cb12015-08-03 10:38:08 -0700871 // Recursively build the list of files to copy.
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800872 sc.Printf("pull: building file list...");
873 std::vector<copyinfo> file_list;
874 if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
Josh Gao204d21e2015-11-02 16:45:47 -0800875 return false;
876 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700877
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800878 sc.ComputeExpectedTotalBytes(file_list);
879
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800880 int pulled = 0;
881 int skipped = 0;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800882 for (const copyinfo &ci : file_list) {
Josh Gaocb094c62015-11-03 14:44:04 -0800883 if (!ci.skip) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800884 if (S_ISDIR(ci.mode)) {
885 // Entry is for an empty directory, create it and continue.
886 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800887 if (!mkdirs(ci.lpath)) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800888 sc.Error("failed to create directory '%s': %s",
Josh Gaoa3b6a062015-11-09 11:12:14 -0800889 ci.lpath.c_str(), strerror(errno));
Josh Gaoa90563e2015-11-04 14:57:04 -0800890 return false;
891 }
892 pulled++;
893 continue;
894 }
895
Josh Gaoa3b6a062015-11-09 11:12:14 -0800896 if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700897 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800898 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700899
Josh Gaoa3b6a062015-11-09 11:12:14 -0800900 if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700901 return false;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700902 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800903 pulled++;
904 } else {
905 skipped++;
906 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800907 }
908
Elliott Hughes78a37a52015-12-08 16:01:15 -0800909 sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s", rpath.c_str(),
Josh Gaod20cf382015-11-03 15:23:03 -0800910 pulled, (pulled == 1) ? "" : "s", skipped,
911 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -0700912 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800913}
914
Josh Gao5d093b22015-10-30 16:57:19 -0700915bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
916 bool copy_attrs) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700917 SyncConnection sc;
918 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800919
Josh Gao5d093b22015-10-30 16:57:19 -0700920 bool success = true;
Josh Gao5d093b22015-10-30 16:57:19 -0700921 struct stat st;
Josh Gaoa5cea712015-11-07 15:27:26 -0800922 bool dst_exists = true;
923
924 if (stat(dst, &st) == -1) {
925 dst_exists = false;
926
927 // If we're only pulling one path, the destination path might point to
Josh Gao5d093b22015-10-30 16:57:19 -0700928 // a path that doesn't exist yet.
Josh Gaoa5cea712015-11-07 15:27:26 -0800929 if (srcs.size() == 1 && errno == ENOENT) {
930 // However, its parent must exist.
931 struct stat parent_st;
932 if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
933 sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
934 return false;
935 }
936 } else {
937 sc.Error("failed to access '%s': %s", dst, strerror(errno));
Josh Gao5d093b22015-10-30 16:57:19 -0700938 return false;
939 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800940 }
941
Josh Gao8acf06c2015-11-07 15:38:19 -0800942 bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
943 if (!dst_isdir) {
Josh Gao5d093b22015-10-30 16:57:19 -0700944 if (srcs.size() > 1) {
945 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700946 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800947 } else {
Josh Gao5d093b22015-10-30 16:57:19 -0700948 size_t dst_len = strlen(dst);
Josh Gaoa5cea712015-11-07 15:27:26 -0800949
950 // A path that ends with a slash doesn't have to be a directory if
951 // it doesn't exist yet.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800952 if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
Josh Gao5d093b22015-10-30 16:57:19 -0700953 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700954 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700955 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800956 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800957 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700958
Josh Gao5d093b22015-10-30 16:57:19 -0700959 for (const char* src_path : srcs) {
960 const char* dst_path = dst;
Elliott Hughes7b43fa52015-12-17 17:05:29 -0800961 unsigned src_mode, src_time, src_size;
962 if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) {
Josh Gaod9a2fd62015-12-09 14:03:30 -0800963 sc.Error("failed to stat remote object '%s'", src_path);
Josh Gaoa5cea712015-11-07 15:27:26 -0800964 return false;
965 }
966 if (src_mode == 0) {
Josh Gao5d093b22015-10-30 16:57:19 -0700967 sc.Error("remote object '%s' does not exist", src_path);
968 success = false;
969 continue;
970 }
971
Josh Gaod9a2fd62015-12-09 14:03:30 -0800972 bool src_isdir = S_ISDIR(src_mode);
973 if (S_ISLNK(src_mode)) {
974 src_isdir = remote_symlink_isdir(sc, src_path);
975 }
976
977 if ((src_mode & (S_IFREG | S_IFDIR | S_IFBLK | S_IFCHR)) == 0) {
978 sc.Error("skipping remote object '%s' (mode = 0o%o)", src_path, src_mode);
979 continue;
980 }
981
982 if (src_isdir) {
Josh Gao8acf06c2015-11-07 15:38:19 -0800983 std::string dst_dir = dst;
984
985 // If the destination path existed originally, the source directory
986 // should be copied as a child of the destination.
987 if (dst_exists) {
988 if (!dst_isdir) {
989 sc.Error("target '%s' is not a directory", dst);
990 return false;
991 }
992 if (!adb_is_separator(dst_dir.back())) {
993 dst_dir.push_back(OS_PATH_SEPARATOR);
994 }
995 dst_dir.append(adb_basename(src_path));
996 }
997
Josh Gaod9a2fd62015-12-09 14:03:30 -0800998 success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
Josh Gao5d093b22015-10-30 16:57:19 -0700999 continue;
1000 } else {
Josh Gaod9a2fd62015-12-09 14:03:30 -08001001 std::string path_holder;
1002 if (dst_isdir) {
1003 // If we're copying a remote file to a local directory, we
1004 // really want to copy to local_dir + OS_PATH_SEPARATOR +
1005 // basename(remote).
1006 path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
1007 adb_basename(src_path).c_str());
1008 dst_path = path_holder.c_str();
1009 }
1010
Elliott Hughes7b43fa52015-12-17 17:05:29 -08001011 sc.SetExpectedTotalBytes(src_size);
Josh Gaod9a2fd62015-12-09 14:03:30 -08001012 if (!sync_recv(sc, src_path, dst_path)) {
1013 success = false;
1014 continue;
1015 }
1016
1017 if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) {
1018 success = false;
1019 continue;
1020 }
Josh Gao5d093b22015-10-30 16:57:19 -07001021 }
1022 }
1023
Josh Gao5d093b22015-10-30 16:57:19 -07001024 return success;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001025}
1026
Elliott Hughesb628cb12015-08-03 10:38:08 -07001027bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesb628cb12015-08-03 10:38:08 -07001028 SyncConnection sc;
1029 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001030
Josh Gaod20cf382015-11-03 15:23:03 -08001031 return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001032}