blob: 85aaa61413205e12e080b497202ad5b8047c34a0 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Dan Albert76649012015-02-24 15:51:19 -080017#include <dirent.h>
18#include <errno.h>
Spencer Low6001c872015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albert76649012015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albert76649012015-02-24 15:51:19 -080027#include <time.h>
Elliott Hughesae5a6c02015-09-27 12:55:37 -070028#include <unistd.h>
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -070029#include <utime.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080030
Josh Gaocda6a2b2015-11-02 16:45:47 -080031#include <functional>
Elliott Hughesa925dba2015-08-24 14:49:43 -070032#include <memory>
Elliott Hughes6d929972015-10-27 13:40:35 -070033#include <vector>
Elliott Hughesa925dba2015-08-24 14:49:43 -070034
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080035#include "sysdeps.h"
Dan Albert76649012015-02-24 15:51:19 -080036
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080037#include "adb.h"
38#include "adb_client.h"
Dan Albertcc731cc2015-02-24 21:26:58 -080039#include "adb_io.h"
Alex Vallée14216142015-05-06 17:22:25 -040040#include "adb_utils.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080041#include "file_sync_service.h"
Elliott Hughesb708d162015-10-27 16:03:15 -070042#include "line_printer.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043
Elliott Hughes4f713192015-12-04 22:00:26 -080044#include <android-base/file.h>
45#include <android-base/strings.h>
46#include <android-base/stringprintf.h>
Elliott Hughes5c742702015-07-30 17:42:01 -070047
Elliott Hughesaa245492015-08-03 10:38:08 -070048struct syncsendbuf {
49 unsigned id;
50 unsigned size;
51 char data[SYNC_DATA_MAX];
52};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080053
Elliott Hughesa00e6ef2015-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 Hughesaa245492015-08-03 10:38:08 -070085class SyncConnection {
86 public:
Elliott Hughesa00e6ef2015-12-17 17:05:29 -080087 SyncConnection()
88 : total_bytes_(0),
89 start_time_ms_(CurrentTimeMs()),
90 expected_total_bytes_(0),
Josh Gaoda811952016-02-19 15:55:55 -080091 expect_multiple_files_(false),
92 expect_done_(false) {
Elliott Hughesaa245492015-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 Hughesb708d162015-10-27 16:03:15 -070098 Error("connect failed: %s", error.c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -070099 }
100 }
101
102 ~SyncConnection() {
103 if (!IsValid()) return;
104
Spencer Low351ecd12015-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 Hughesaa245492015-08-03 10:38:08 -0700114 adb_close(fd);
Elliott Hughes77f539a2015-12-08 16:01:15 -0800115
116 line_printer_.KeepInfoLine();
Elliott Hughesaa245492015-08-03 10:38:08 -0700117 }
118
119 bool IsValid() { return fd >= 0; }
120
Josh Gaoda811952016-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 Hughesae5a6c02015-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 Hughesb708d162015-10-27 16:03:15 -0700134 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-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 Hughes6d929972015-10-27 13:40:35 -0700141 std::vector<char> buf(sizeof(SyncRequest) + path_length);
142 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesae5a6c02015-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 Hughes6d929972015-10-27 13:40:35 -0700148 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesae5a6c02015-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 Hughescc65c3b2015-11-20 22:01:06 -0800154 const char* lpath, const char* rpath,
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800155 unsigned mtime,
156 const char* data, size_t data_length) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700157 size_t path_length = strlen(path_and_mode);
158 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700159 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700160 errno = ENAMETOOLONG;
161 return false;
162 }
163
Elliott Hughes6d929972015-10-27 13:40:35 -0700164 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800165 sizeof(SyncRequest) + data_length +
166 sizeof(SyncRequest));
Elliott Hughes6d929972015-10-27 13:40:35 -0700167 char* p = &buf[0];
Elliott Hughesae5a6c02015-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 Hughescc65c3b2015-11-20 22:01:06 -0800188 WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
Josh Gaoda811952016-02-19 15:55:55 -0800189 expect_done_ = true;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800190 total_bytes_ += data_length;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700191 return true;
192 }
193
Elliott Hughes6aab58c2015-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 Hughescc65c3b2015-11-20 22:01:06 -0800213 Error("opening '%s' locally failed: %s", lpath, strerror(errno));
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800214 return false;
215 }
216
217 syncsendbuf sbuf;
218 sbuf.id = ID_DATA;
219 while (true) {
Elliott Hughescc65c3b2015-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 Hughes6aab58c2015-11-20 17:35:17 -0800226 break;
227 }
228
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800229 sbuf.size = bytes_read;
230 WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800231
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800232 total_bytes_ += bytes_read;
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800233 bytes_copied += bytes_read;
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800234
Josh Gaoda811952016-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 Hughesa00e6ef2015-12-17 17:05:29 -0800240 ReportProgress(rpath, bytes_copied, total_size);
Elliott Hughes6aab58c2015-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 Gaoda811952016-02-19 15:55:55 -0800248 expect_done_ = true;
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800249 return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800250 }
251
Elliott Hughesae5a6c02015-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 Gaoda811952016-02-19 15:55:55 -0800255 Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700256 return false;
257 }
258 if (msg.status.id == ID_OKAY) {
Josh Gaoda811952016-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 Hughesae5a6c02015-09-27 12:55:37 -0700266 }
267 if (msg.status.id != ID_FAIL) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700268 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700269 return false;
270 }
Elliott Hughes8b43c3e2015-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 Hughes6d929972015-10-27 13:40:35 -0700275 std::vector<char> buf(msg.status.msglen + 1);
276 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700277 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
278 from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700279 return false;
280 }
Elliott Hughes6d929972015-10-27 13:40:35 -0700281 buf[msg.status.msglen] = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700282 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700283 return false;
284 }
285
Elliott Hughesb708d162015-10-27 16:03:15 -0700286 std::string TransferRate() {
287 uint64_t ms = CurrentTimeMs() - start_time_ms_;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800288 if (total_bytes_ == 0 || ms == 0) return "";
Elliott Hughesb708d162015-10-27 16:03:15 -0700289
290 double s = static_cast<double>(ms) / 1000LL;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800291 double rate = (static_cast<double>(total_bytes_) / s) / (1024*1024);
Elliott Hughesb708d162015-10-27 16:03:15 -0700292 return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800293 rate, total_bytes_, s);
Elliott Hughesb708d162015-10-27 16:03:15 -0700294 }
295
Elliott Hughesa00e6ef2015-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 Hughesb708d162015-10-27 16:03:15 -0700323 }
324
Josh Gao983c41c2015-11-02 17:15:57 -0800325 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
326 std::string s;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800327
Josh Gao983c41c2015-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 Hughesa00e6ef2015-12-17 17:05:29 -0800333 line_printer_.Print(s, LinePrinter::INFO);
Josh Gao983c41c2015-11-02 17:15:57 -0800334 }
335
Elliott Hughesb708d162015-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 Hughes77f539a2015-12-08 16:01:15 -0800344 line_printer_.Print(s, LinePrinter::ERROR);
Elliott Hughesb708d162015-10-27 16:03:15 -0700345 }
346
Josh Gao21abf5a2015-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 Hughes77f539a2015-12-08 16:01:15 -0800355 line_printer_.Print(s, LinePrinter::WARNING);
Josh Gao21abf5a2015-11-07 17:18:44 -0800356 }
357
Elliott Hughesa00e6ef2015-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 Hughesaa245492015-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 Hughesb708d162015-10-27 16:03:15 -0700380 uint64_t start_time_ms_;
381
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800382 uint64_t expected_total_bytes_;
383 bool expect_multiple_files_;
Josh Gaoda811952016-02-19 15:55:55 -0800384 bool expect_done_;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800385
Elliott Hughesb708d162015-10-27 16:03:15 -0700386 LinePrinter line_printer_;
Elliott Hughesaa245492015-08-03 10:38:08 -0700387
Spencer Low351ecd12015-10-14 17:32:44 -0700388 bool SendQuit() {
389 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesaa245492015-08-03 10:38:08 -0700390 }
391
Elliott Hughescc65c3b2015-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 Hughesb708d162015-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 Hughesaa245492015-08-03 10:38:08 -0700417 }
418};
419
Josh Gaocda6a2b2015-11-02 16:45:47 -0800420typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesaa245492015-08-03 10:38:08 -0700421
Josh Gaocda6a2b2015-11-02 16:45:47 -0800422static bool sync_ls(SyncConnection& sc, const char* path,
423 std::function<sync_ls_cb> func) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700424 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700425
426 while (true) {
427 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700428 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesaa245492015-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 Hughesf4465202015-08-24 14:27:03 -0700433 size_t len = msg.dent.namelen;
Elliott Hughesaa245492015-08-03 10:38:08 -0700434 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800435
Elliott Hughes5c742702015-07-30 17:42:01 -0700436 char buf[257];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700437 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800438 buf[len] = 0;
439
Josh Gaocda6a2b2015-11-02 16:45:47 -0800440 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800441 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800442}
443
Elliott Hughesaa245492015-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 Projectdd7bc332009-03-03 19:32:55 -0800446 syncmsg msg;
Elliott Hughesaa245492015-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 Projectdd7bc332009-03-03 19:32:55 -0800449 }
450
Elliott Hughesf4465202015-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 Projectdd7bc332009-03-03 19:32:55 -0800454
Elliott Hughesaa245492015-08-03 10:38:08 -0700455 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800456}
457
Elliott Hughesaa245492015-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 Hughesae5a6c02015-09-27 12:55:37 -0700460 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800461}
462
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700463static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesb708d162015-10-27 16:03:15 -0700464 unsigned mtime, mode_t mode)
Elliott Hughesae5a6c02015-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 Hughesb708d162015-10-27 16:03:15 -0700473 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700474 return false;
475 }
476 buf[data_length++] = '\0';
477
Elliott Hughescc65c3b2015-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 Hughesae5a6c02015-09-27 12:55:37 -0700481 return sc.CopyDone(lpath, rpath);
482#endif
483 }
484
485 if (!S_ISREG(mode)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700486 sc.Error("local file '%s' has unsupported mode: 0o%o", lpath, mode);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700487 return false;
488 }
489
490 struct stat st;
491 if (stat(lpath, &st) == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700492 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-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 Hughesb708d162015-10-27 16:03:15 -0700498 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700499 return false;
500 }
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800501 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
502 data.data(), data.size())) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700503 return false;
504 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700505 } else {
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800506 if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700507 return false;
508 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700509 }
510 return sc.CopyDone(lpath, rpath);
511}
512
Elliott Hughesb708d162015-10-27 16:03:15 -0700513static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700514 unsigned size = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700515 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner76f2a932014-03-11 17:55:59 -0700516
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700517 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800518
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700519 adb_unlink(lpath);
Josh Gaof6e65e32015-11-17 14:08:20 -0800520 const std::string dirpath = adb_dirname(lpath);
521 if (!mkdirs(dirpath.c_str())) {
522 sc.Error("failed to create parent directory '%s': %s", dirpath.c_str(), strerror(errno));
Josh Gao45b6fc82015-11-04 14:51:23 -0800523 return false;
524 }
525
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700526 int lfd = adb_creat(lpath, 0644);
527 if (lfd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700528 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700529 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800530 }
531
Elliott Hughesb708d162015-10-27 16:03:15 -0700532 uint64_t bytes_copied = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700533 while (true) {
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700534 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700535 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700536 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700537 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700538 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800539 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800540
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700541 if (msg.data.id == ID_DONE) break;
542
543 if (msg.data.id != ID_DATA) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800544 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700545 adb_unlink(lpath);
546 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700547 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800548 }
549
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700550 if (msg.data.size > sc.max) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700551 sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800552 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700553 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700554 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800555 }
556
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700557 char buffer[SYNC_DATA_MAX];
558 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800559 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700560 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700561 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800562 }
563
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700564 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700565 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700566 adb_close(lfd);
567 adb_unlink(lpath);
568 return false;
569 }
570
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800571 sc.total_bytes_ += msg.data.size;
Mark Lindner76f2a932014-03-11 17:55:59 -0700572
Elliott Hughesb708d162015-10-27 16:03:15 -0700573 bytes_copied += msg.data.size;
574
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800575 sc.ReportProgress(rpath, bytes_copied, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800576 }
577
578 adb_close(lfd);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700579 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800580}
581
Elliott Hughesaa245492015-08-03 10:38:08 -0700582bool do_sync_ls(const char* path) {
583 SyncConnection sc;
584 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800585
Josh Gaocda6a2b2015-11-02 16:45:47 -0800586 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
587 const char* name) {
588 printf("%08x %08x %08x %s\n", mode, size, time, name);
589 });
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800590}
591
Elliott Hughesaa245492015-08-03 10:38:08 -0700592static bool IsDotOrDotDot(const char* name) {
593 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
594}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800595
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800596static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800597 const std::string& lpath,
598 const std::string& rpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800599 std::vector<copyinfo> dirlist;
Josh Gaod9731572015-11-03 15:23:03 -0800600 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
Elliott Hughesaa245492015-08-03 10:38:08 -0700601 if (!dir) {
Josh Gaod9731572015-11-03 15:23:03 -0800602 sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800603 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800604 }
605
Josh Gao65800962015-11-04 14:57:04 -0800606 bool empty_dir = true;
Elliott Hughesb708d162015-10-27 16:03:15 -0700607 dirent* de;
Elliott Hughesaa245492015-08-03 10:38:08 -0700608 while ((de = readdir(dir.get()))) {
Josh Gao65800962015-11-04 14:57:04 -0800609 if (IsDotOrDotDot(de->d_name)) {
610 continue;
611 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700612
Josh Gao65800962015-11-04 14:57:04 -0800613 empty_dir = false;
Josh Gaod9731572015-11-03 15:23:03 -0800614 std::string stat_path = lpath + de->d_name;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800615
Elliott Hughesaa245492015-08-03 10:38:08 -0700616 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800617 if (lstat(stat_path.c_str(), &st) == -1) {
Josh Gaod9731572015-11-03 15:23:03 -0800618 sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
619 strerror(errno));
Josh Gao12a2ae92015-11-07 15:27:26 -0800620 continue;
621 }
622
Josh Gaof2642242015-12-09 14:03:30 -0800623 copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
Josh Gao12a2ae92015-11-07 15:27:26 -0800624 if (S_ISDIR(st.st_mode)) {
625 dirlist.push_back(ci);
626 } else {
627 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
628 sc.Error("skipping special file '%s'", lpath.c_str());
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800629 ci.skip = true;
Josh Gao12a2ae92015-11-07 15:27:26 -0800630 } else {
631 ci.time = st.st_mtime;
632 ci.size = st.st_size;
Josh Gao12a2ae92015-11-07 15:27:26 -0800633 }
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800634 file_list->push_back(ci);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800635 }
636 }
637
Elliott Hughesaa245492015-08-03 10:38:08 -0700638 // Close this directory and recurse.
639 dir.reset();
Josh Gao65800962015-11-04 14:57:04 -0800640
641 // Add the current directory to the list if it was empty, to ensure that
642 // it gets created.
643 if (empty_dir) {
644 // TODO(b/25566053): Make pushing empty directories work.
645 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao21abf5a2015-11-07 17:18:44 -0800646 sc.Warning("skipping empty directory '%s'", lpath.c_str());
Josh Gaof2642242015-12-09 14:03:30 -0800647 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
Josh Gao65800962015-11-04 14:57:04 -0800648 ci.skip = true;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800649 file_list->push_back(ci);
Josh Gao65800962015-11-04 14:57:04 -0800650 return true;
651 }
652
Josh Gaocda6a2b2015-11-02 16:45:47 -0800653 for (const copyinfo& ci : dirlist) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800654 local_build_list(sc, file_list, ci.lpath, ci.rpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800655 }
656
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800657 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800658}
659
Josh Gaod9731572015-11-03 15:23:03 -0800660static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
661 std::string rpath, bool check_timestamps,
662 bool list_only) {
663 // Make sure that both directory paths end in a slash.
Josh Gao1a025302015-11-09 11:12:14 -0800664 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800665 ensure_trailing_separators(lpath, rpath);
Josh Gaod9731572015-11-03 15:23:03 -0800666
667 // Recursively build the list of files to copy.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800668 std::vector<copyinfo> file_list;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800669 int pushed = 0;
670 int skipped = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800671 if (!local_build_list(sc, &file_list, lpath, rpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700672 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800673 }
674
Elliott Hughesaa245492015-08-03 10:38:08 -0700675 if (check_timestamps) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800676 for (const copyinfo& ci : file_list) {
Josh Gao1a025302015-11-09 11:12:14 -0800677 if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
Josh Gaod9731572015-11-03 15:23:03 -0800678 return false;
679 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800680 }
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800681 for (copyinfo& ci : file_list) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800682 unsigned int timestamp, mode, size;
Josh Gaod9731572015-11-03 15:23:03 -0800683 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
684 return false;
685 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800686 if (size == ci.size) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800687 // For links, we cannot update the atime/mtime.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800688 if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
689 (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800690 ci.skip = true;
Elliott Hughesaa245492015-08-03 10:38:08 -0700691 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800692 }
693 }
694 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800695
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800696 sc.ComputeExpectedTotalBytes(file_list);
697
698 for (const copyinfo& ci : file_list) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800699 if (!ci.skip) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700700 if (list_only) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800701 sc.Error("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
Elliott Hughesb708d162015-10-27 16:03:15 -0700702 } else {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800703 if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) {
Josh Gaod9731572015-11-03 15:23:03 -0800704 return false;
Elliott Hughesb708d162015-10-27 16:03:15 -0700705 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800706 }
707 pushed++;
708 } else {
709 skipped++;
710 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800711 }
712
Elliott Hughes77f539a2015-12-08 16:01:15 -0800713 sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s", rpath.c_str(),
Josh Gaod9731572015-11-03 15:23:03 -0800714 pushed, (pushed == 1) ? "" : "s", skipped,
715 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700716 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800717}
718
Josh Gao05786772015-10-30 16:57:19 -0700719bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700720 SyncConnection sc;
721 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800722
Josh Gao05786772015-10-30 16:57:19 -0700723 bool success = true;
Josh Gao12a2ae92015-11-07 15:27:26 -0800724 unsigned dst_mode;
725 if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false;
726 bool dst_exists = (dst_mode != 0);
Josh Gao07db1192015-11-07 15:38:19 -0800727 bool dst_isdir = S_ISDIR(dst_mode);
Josh Gao05786772015-10-30 16:57:19 -0700728
Josh Gao07db1192015-11-07 15:38:19 -0800729 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700730 if (srcs.size() > 1) {
731 sc.Error("target '%s' is not a directory", dst);
732 return false;
733 } else {
734 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -0800735
736 // A path that ends with a slash doesn't have to be a directory if
737 // it doesn't exist yet.
738 if (dst[dst_len - 1] == '/' && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -0700739 sc.Error("failed to access '%s': Not a directory", dst);
740 return false;
741 }
742 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700743 }
Josh Gao05786772015-10-30 16:57:19 -0700744
745 for (const char* src_path : srcs) {
746 const char* dst_path = dst;
747 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800748 if (stat(src_path, &st) == -1) {
Josh Gao05786772015-10-30 16:57:19 -0700749 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
750 success = false;
751 continue;
752 }
753
754 if (S_ISDIR(st.st_mode)) {
Josh Gao07db1192015-11-07 15:38:19 -0800755 std::string dst_dir = dst;
756
757 // If the destination path existed originally, the source directory
758 // should be copied as a child of the destination.
759 if (dst_exists) {
760 if (!dst_isdir) {
761 sc.Error("target '%s' is not a directory", dst);
762 return false;
763 }
764 // dst is a POSIX path, so we don't want to use the sysdeps
765 // helpers here.
766 if (dst_dir.back() != '/') {
767 dst_dir.push_back('/');
768 }
769 dst_dir.append(adb_basename(src_path));
770 }
771
772 success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(),
773 false, false);
Josh Gao05786772015-10-30 16:57:19 -0700774 continue;
775 }
776
777 std::string path_holder;
Josh Gao07db1192015-11-07 15:38:19 -0800778 if (dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700779 // If we're copying a local file to a remote directory,
780 // we really want to copy to remote_dir + "/" + local_filename.
Josh Gao323899b2016-02-03 14:55:24 -0800781 path_holder = dst_path;
782 if (path_holder.back() != '/') {
783 path_holder.push_back('/');
784 }
785 path_holder += adb_basename(src_path);
Josh Gao05786772015-10-30 16:57:19 -0700786 dst_path = path_holder.c_str();
787 }
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800788 sc.SetExpectedTotalBytes(st.st_size);
Josh Gao05786772015-10-30 16:57:19 -0700789 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
790 }
791
Josh Gao05786772015-10-30 16:57:19 -0700792 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800793}
794
Josh Gaof2642242015-12-09 14:03:30 -0800795static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) {
796 unsigned mode;
797 std::string dir_path = rpath;
798 dir_path.push_back('/');
799 if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) {
800 sc.Error("failed to stat remote symlink '%s'", dir_path.c_str());
801 return false;
802 }
803 return S_ISDIR(mode);
804}
805
Josh Gaocda6a2b2015-11-02 16:45:47 -0800806static bool remote_build_list(SyncConnection& sc,
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800807 std::vector<copyinfo>* file_list,
Josh Gaod9731572015-11-03 15:23:03 -0800808 const std::string& rpath,
809 const std::string& lpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800810 std::vector<copyinfo> dirlist;
Josh Gaof2642242015-12-09 14:03:30 -0800811 std::vector<copyinfo> linklist;
Josh Gao65800962015-11-04 14:57:04 -0800812 bool empty_dir = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800813
Elliott Hughesaa245492015-08-03 10:38:08 -0700814 // Put the files/dirs in rpath on the lists.
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800815 auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
Josh Gao65800962015-11-04 14:57:04 -0800816 if (IsDotOrDotDot(name)) {
817 return;
818 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800819
Josh Gao65800962015-11-04 14:57:04 -0800820 // We found a child that isn't '.' or '..'.
821 empty_dir = false;
822
Josh Gaof2642242015-12-09 14:03:30 -0800823 copyinfo ci(lpath, rpath, name, mode);
Josh Gao65800962015-11-04 14:57:04 -0800824 if (S_ISDIR(mode)) {
825 dirlist.push_back(ci);
Josh Gaof2642242015-12-09 14:03:30 -0800826 } else if (S_ISLNK(mode)) {
827 linklist.push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -0800828 } else {
Josh Gaof2642242015-12-09 14:03:30 -0800829 ci.time = time;
830 ci.size = size;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800831 file_list->push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -0800832 }
833 };
834
Josh Gaod9731572015-11-03 15:23:03 -0800835 if (!sync_ls(sc, rpath.c_str(), callback)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700836 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800837 }
838
Josh Gaof2642242015-12-09 14:03:30 -0800839 // Add the current directory to the list if it was empty, to ensure that it gets created.
Josh Gao65800962015-11-04 14:57:04 -0800840 if (empty_dir) {
Josh Gaof2642242015-12-09 14:03:30 -0800841 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(rpath), S_IFDIR);
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800842 file_list->push_back(ci);
Josh Gao65800962015-11-04 14:57:04 -0800843 return true;
844 }
845
Josh Gaof2642242015-12-09 14:03:30 -0800846 // Check each symlink we found to see whether it's a file or directory.
847 for (copyinfo& link_ci : linklist) {
848 if (remote_symlink_isdir(sc, link_ci.rpath)) {
849 dirlist.emplace_back(std::move(link_ci));
850 } else {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800851 file_list->emplace_back(std::move(link_ci));
Josh Gaof2642242015-12-09 14:03:30 -0800852 }
853 }
854
Elliott Hughesaa245492015-08-03 10:38:08 -0700855 // Recurse into each directory we found.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800856 while (!dirlist.empty()) {
857 copyinfo current = dirlist.back();
858 dirlist.pop_back();
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800859 if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700860 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800861 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800862 }
863
Elliott Hughesaa245492015-08-03 10:38:08 -0700864 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800865}
866
Josh Gao1a025302015-11-09 11:12:14 -0800867static int set_time_and_mode(const std::string& lpath, time_t time,
868 unsigned int mode) {
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700869 struct utimbuf times = { time, time };
Josh Gao1a025302015-11-09 11:12:14 -0800870 int r1 = utime(lpath.c_str(), &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700871
872 /* use umask for permissions */
Josh Gaocda6a2b2015-11-02 16:45:47 -0800873 mode_t mask = umask(0000);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700874 umask(mask);
Josh Gao1a025302015-11-09 11:12:14 -0800875 int r2 = chmod(lpath.c_str(), mode & ~mask);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700876
Spencer Low363af562015-11-07 18:51:54 -0800877 return r1 ? r1 : r2;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700878}
879
Josh Gaod9731572015-11-03 15:23:03 -0800880static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
881 std::string lpath, bool copy_attrs) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700882 // Make sure that both directory paths end in a slash.
Josh Gao12a2ae92015-11-07 15:27:26 -0800883 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800884 ensure_trailing_separators(lpath, rpath);
Riley Andrews4d04d242014-12-12 13:12:36 -0800885
Elliott Hughesaa245492015-08-03 10:38:08 -0700886 // Recursively build the list of files to copy.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800887 sc.Printf("pull: building file list...");
888 std::vector<copyinfo> file_list;
889 if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800890 return false;
891 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700892
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800893 sc.ComputeExpectedTotalBytes(file_list);
894
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800895 int pulled = 0;
896 int skipped = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800897 for (const copyinfo &ci : file_list) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800898 if (!ci.skip) {
Josh Gao65800962015-11-04 14:57:04 -0800899 if (S_ISDIR(ci.mode)) {
900 // Entry is for an empty directory, create it and continue.
901 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao1a025302015-11-09 11:12:14 -0800902 if (!mkdirs(ci.lpath)) {
Josh Gao65800962015-11-04 14:57:04 -0800903 sc.Error("failed to create directory '%s': %s",
Josh Gao1a025302015-11-09 11:12:14 -0800904 ci.lpath.c_str(), strerror(errno));
Josh Gao65800962015-11-04 14:57:04 -0800905 return false;
906 }
907 pulled++;
908 continue;
909 }
910
Josh Gao1a025302015-11-09 11:12:14 -0800911 if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700912 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800913 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700914
Josh Gao1a025302015-11-09 11:12:14 -0800915 if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700916 return false;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700917 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800918 pulled++;
919 } else {
920 skipped++;
921 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800922 }
923
Elliott Hughes77f539a2015-12-08 16:01:15 -0800924 sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s", rpath.c_str(),
Josh Gaod9731572015-11-03 15:23:03 -0800925 pulled, (pulled == 1) ? "" : "s", skipped,
926 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700927 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800928}
929
Josh Gao05786772015-10-30 16:57:19 -0700930bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
931 bool copy_attrs) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700932 SyncConnection sc;
933 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800934
Josh Gao05786772015-10-30 16:57:19 -0700935 bool success = true;
Josh Gao05786772015-10-30 16:57:19 -0700936 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800937 bool dst_exists = true;
938
939 if (stat(dst, &st) == -1) {
940 dst_exists = false;
941
942 // If we're only pulling one path, the destination path might point to
Josh Gao05786772015-10-30 16:57:19 -0700943 // a path that doesn't exist yet.
Josh Gao12a2ae92015-11-07 15:27:26 -0800944 if (srcs.size() == 1 && errno == ENOENT) {
945 // However, its parent must exist.
946 struct stat parent_st;
947 if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
948 sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
949 return false;
950 }
951 } else {
952 sc.Error("failed to access '%s': %s", dst, strerror(errno));
Josh Gao05786772015-10-30 16:57:19 -0700953 return false;
954 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800955 }
956
Josh Gao07db1192015-11-07 15:38:19 -0800957 bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
958 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700959 if (srcs.size() > 1) {
960 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700961 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800962 } else {
Josh Gao05786772015-10-30 16:57:19 -0700963 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -0800964
965 // A path that ends with a slash doesn't have to be a directory if
966 // it doesn't exist yet.
Josh Gao1a025302015-11-09 11:12:14 -0800967 if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -0700968 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700969 return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700970 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800971 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800972 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700973
Josh Gao05786772015-10-30 16:57:19 -0700974 for (const char* src_path : srcs) {
975 const char* dst_path = dst;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800976 unsigned src_mode, src_time, src_size;
977 if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) {
Josh Gaof2642242015-12-09 14:03:30 -0800978 sc.Error("failed to stat remote object '%s'", src_path);
Josh Gao12a2ae92015-11-07 15:27:26 -0800979 return false;
980 }
981 if (src_mode == 0) {
Josh Gao05786772015-10-30 16:57:19 -0700982 sc.Error("remote object '%s' does not exist", src_path);
983 success = false;
984 continue;
985 }
986
Josh Gaof2642242015-12-09 14:03:30 -0800987 bool src_isdir = S_ISDIR(src_mode);
988 if (S_ISLNK(src_mode)) {
989 src_isdir = remote_symlink_isdir(sc, src_path);
990 }
991
992 if ((src_mode & (S_IFREG | S_IFDIR | S_IFBLK | S_IFCHR)) == 0) {
993 sc.Error("skipping remote object '%s' (mode = 0o%o)", src_path, src_mode);
994 continue;
995 }
996
997 if (src_isdir) {
Josh Gao07db1192015-11-07 15:38:19 -0800998 std::string dst_dir = dst;
999
1000 // If the destination path existed originally, the source directory
1001 // should be copied as a child of the destination.
1002 if (dst_exists) {
1003 if (!dst_isdir) {
1004 sc.Error("target '%s' is not a directory", dst);
1005 return false;
1006 }
1007 if (!adb_is_separator(dst_dir.back())) {
1008 dst_dir.push_back(OS_PATH_SEPARATOR);
1009 }
1010 dst_dir.append(adb_basename(src_path));
1011 }
1012
Josh Gaof2642242015-12-09 14:03:30 -08001013 success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
Josh Gao05786772015-10-30 16:57:19 -07001014 continue;
1015 } else {
Josh Gaof2642242015-12-09 14:03:30 -08001016 std::string path_holder;
1017 if (dst_isdir) {
1018 // If we're copying a remote file to a local directory, we
1019 // really want to copy to local_dir + OS_PATH_SEPARATOR +
1020 // basename(remote).
1021 path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
1022 adb_basename(src_path).c_str());
1023 dst_path = path_holder.c_str();
1024 }
1025
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001026 sc.SetExpectedTotalBytes(src_size);
Josh Gaof2642242015-12-09 14:03:30 -08001027 if (!sync_recv(sc, src_path, dst_path)) {
1028 success = false;
1029 continue;
1030 }
1031
1032 if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) {
1033 success = false;
1034 continue;
1035 }
Josh Gao05786772015-10-30 16:57:19 -07001036 }
1037 }
1038
Josh Gao05786772015-10-30 16:57:19 -07001039 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001040}
1041
Elliott Hughesaa245492015-08-03 10:38:08 -07001042bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001043 SyncConnection sc;
1044 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001045
Josh Gaod9731572015-11-03 15:23:03 -08001046 return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001047}