blob: 51fc1433d14faa8912ad06e555f828a3dc1e07a6 [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),
91 expect_multiple_files_(false) {
Elliott Hughesaa245492015-08-03 10:38:08 -070092 max = SYNC_DATA_MAX; // TODO: decide at runtime.
93
94 std::string error;
95 fd = adb_connect("sync:", &error);
96 if (fd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -070097 Error("connect failed: %s", error.c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -070098 }
99 }
100
101 ~SyncConnection() {
102 if (!IsValid()) return;
103
Spencer Low351ecd12015-10-14 17:32:44 -0700104 if (SendQuit()) {
105 // We sent a quit command, so the server should be doing orderly
106 // shutdown soon. But if we encountered an error while we were using
107 // the connection, the server might still be sending data (before
108 // doing orderly shutdown), in which case we won't wait for all of
109 // the data nor the coming orderly shutdown. In the common success
110 // case, this will wait for the server to do orderly shutdown.
111 ReadOrderlyShutdown(fd);
112 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700113 adb_close(fd);
Elliott Hughes77f539a2015-12-08 16:01:15 -0800114
115 line_printer_.KeepInfoLine();
Elliott Hughesaa245492015-08-03 10:38:08 -0700116 }
117
118 bool IsValid() { return fd >= 0; }
119
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700120 bool SendRequest(int id, const char* path_and_mode) {
121 size_t path_length = strlen(path_and_mode);
122 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700123 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700124 errno = ENAMETOOLONG;
125 return false;
126 }
127
128 // Sending header and payload in a single write makes a noticeable
129 // difference to "adb sync" performance.
Elliott Hughes6d929972015-10-27 13:40:35 -0700130 std::vector<char> buf(sizeof(SyncRequest) + path_length);
131 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700132 req->id = id;
133 req->path_length = path_length;
134 char* data = reinterpret_cast<char*>(req + 1);
135 memcpy(data, path_and_mode, path_length);
136
Elliott Hughes6d929972015-10-27 13:40:35 -0700137 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700138 }
139
140 // Sending header, payload, and footer in a single write makes a huge
141 // difference to "adb sync" performance.
142 bool SendSmallFile(const char* path_and_mode,
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800143 const char* lpath, const char* rpath,
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800144 unsigned mtime,
145 const char* data, size_t data_length) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700146 size_t path_length = strlen(path_and_mode);
147 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700148 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700149 errno = ENAMETOOLONG;
150 return false;
151 }
152
Elliott Hughes6d929972015-10-27 13:40:35 -0700153 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800154 sizeof(SyncRequest) + data_length +
155 sizeof(SyncRequest));
Elliott Hughes6d929972015-10-27 13:40:35 -0700156 char* p = &buf[0];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700157
158 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
159 req_send->id = ID_SEND;
160 req_send->path_length = path_length;
161 p += sizeof(SyncRequest);
162 memcpy(p, path_and_mode, path_length);
163 p += path_length;
164
165 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
166 req_data->id = ID_DATA;
167 req_data->path_length = data_length;
168 p += sizeof(SyncRequest);
169 memcpy(p, data, data_length);
170 p += data_length;
171
172 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
173 req_done->id = ID_DONE;
174 req_done->path_length = mtime;
175 p += sizeof(SyncRequest);
176
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800177 WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800178 total_bytes_ += data_length;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700179 return true;
180 }
181
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800182 bool SendLargeFile(const char* path_and_mode,
183 const char* lpath, const char* rpath,
184 unsigned mtime) {
185 if (!SendRequest(ID_SEND, path_and_mode)) {
186 Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
187 return false;
188 }
189
190 struct stat st;
191 if (stat(lpath, &st) == -1) {
192 Error("cannot stat '%s': %s", lpath, strerror(errno));
193 return false;
194 }
195
196 uint64_t total_size = st.st_size;
197 uint64_t bytes_copied = 0;
198
199 int lfd = adb_open(lpath, O_RDONLY);
200 if (lfd < 0) {
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800201 Error("opening '%s' locally failed: %s", lpath, strerror(errno));
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800202 return false;
203 }
204
205 syncsendbuf sbuf;
206 sbuf.id = ID_DATA;
207 while (true) {
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800208 int bytes_read = adb_read(lfd, sbuf.data, max);
209 if (bytes_read == -1) {
210 Error("reading '%s' locally failed: %s", lpath, strerror(errno));
211 adb_close(lfd);
212 return false;
213 } else if (bytes_read == 0) {
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800214 break;
215 }
216
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800217 sbuf.size = bytes_read;
218 WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800219
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800220 total_bytes_ += bytes_read;
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800221 bytes_copied += bytes_read;
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800222
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800223 ReportProgress(rpath, bytes_copied, total_size);
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800224 }
225
226 adb_close(lfd);
227
228 syncmsg msg;
229 msg.data.id = ID_DONE;
230 msg.data.size = mtime;
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800231 return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800232 }
233
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700234 bool CopyDone(const char* from, const char* to) {
235 syncmsg msg;
236 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700237 Error("failed to copy '%s' to '%s': no ID_DONE: %s", from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700238 return false;
239 }
240 if (msg.status.id == ID_OKAY) {
241 return true;
242 }
243 if (msg.status.id != ID_FAIL) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700244 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700245 return false;
246 }
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700247 return ReportCopyFailure(from, to, msg);
248 }
249
250 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6d929972015-10-27 13:40:35 -0700251 std::vector<char> buf(msg.status.msglen + 1);
252 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700253 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
254 from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700255 return false;
256 }
Elliott Hughes6d929972015-10-27 13:40:35 -0700257 buf[msg.status.msglen] = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700258 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700259 return false;
260 }
261
Elliott Hughesb708d162015-10-27 16:03:15 -0700262 std::string TransferRate() {
263 uint64_t ms = CurrentTimeMs() - start_time_ms_;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800264 if (total_bytes_ == 0 || ms == 0) return "";
Elliott Hughesb708d162015-10-27 16:03:15 -0700265
266 double s = static_cast<double>(ms) / 1000LL;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800267 double rate = (static_cast<double>(total_bytes_) / s) / (1024*1024);
Elliott Hughesb708d162015-10-27 16:03:15 -0700268 return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800269 rate, total_bytes_, s);
Elliott Hughesb708d162015-10-27 16:03:15 -0700270 }
271
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800272 void ReportProgress(const char* file, uint64_t file_copied_bytes, uint64_t file_total_bytes) {
273 char overall_percentage_str[5] = "?";
274 if (expected_total_bytes_ != 0) {
275 int overall_percentage = static_cast<int>(total_bytes_ * 100 / expected_total_bytes_);
276 // If we're pulling symbolic links, we'll pull the target of the link rather than
277 // just create a local link, and that will cause us to go over 100%.
278 if (overall_percentage <= 100) {
279 snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
280 overall_percentage);
281 }
282 }
283
284 if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
285 // This case can happen if we're racing against something that wrote to the file
286 // between our stat and our read, or if we're reading a magic file that lies about
287 // its size. Just show how much we've copied.
288 Printf("[%4s] %s: %" PRId64 "/?", overall_percentage_str, file, file_copied_bytes);
289 } else {
290 // If we're transferring multiple files, we want to know how far through the current
291 // file we are, as well as the overall percentage.
292 if (expect_multiple_files_) {
293 int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
294 Printf("[%4s] %s: %d%%", overall_percentage_str, file, file_percentage);
295 } else {
296 Printf("[%4s] %s", overall_percentage_str, file);
297 }
298 }
Elliott Hughesb708d162015-10-27 16:03:15 -0700299 }
300
Josh Gao983c41c2015-11-02 17:15:57 -0800301 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
302 std::string s;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800303
Josh Gao983c41c2015-11-02 17:15:57 -0800304 va_list ap;
305 va_start(ap, fmt);
306 android::base::StringAppendV(&s, fmt, ap);
307 va_end(ap);
308
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800309 line_printer_.Print(s, LinePrinter::INFO);
Josh Gao983c41c2015-11-02 17:15:57 -0800310 }
311
Elliott Hughesb708d162015-10-27 16:03:15 -0700312 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
313 std::string s = "adb: error: ";
314
315 va_list ap;
316 va_start(ap, fmt);
317 android::base::StringAppendV(&s, fmt, ap);
318 va_end(ap);
319
Elliott Hughes77f539a2015-12-08 16:01:15 -0800320 line_printer_.Print(s, LinePrinter::ERROR);
Elliott Hughesb708d162015-10-27 16:03:15 -0700321 }
322
Josh Gao21abf5a2015-11-07 17:18:44 -0800323 void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
324 std::string s = "adb: warning: ";
325
326 va_list ap;
327 va_start(ap, fmt);
328 android::base::StringAppendV(&s, fmt, ap);
329 va_end(ap);
330
Elliott Hughes77f539a2015-12-08 16:01:15 -0800331 line_printer_.Print(s, LinePrinter::WARNING);
Josh Gao21abf5a2015-11-07 17:18:44 -0800332 }
333
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800334 void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
335 expected_total_bytes_ = 0;
336 for (const copyinfo& ci : file_list) {
337 // Unfortunately, this doesn't work for symbolic links, because we'll copy the
338 // target of the link rather than just creating a link. (But ci.size is the link size.)
339 if (!ci.skip) expected_total_bytes_ += ci.size;
340 }
341 expect_multiple_files_ = true;
342 }
343
344 void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
345 expected_total_bytes_ = expected_total_bytes;
346 expect_multiple_files_ = false;
347 }
348
349 uint64_t total_bytes_;
Elliott Hughesaa245492015-08-03 10:38:08 -0700350
351 // TODO: add a char[max] buffer here, to replace syncsendbuf...
352 int fd;
353 size_t max;
354
355 private:
Elliott Hughesb708d162015-10-27 16:03:15 -0700356 uint64_t start_time_ms_;
357
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800358 uint64_t expected_total_bytes_;
359 bool expect_multiple_files_;
360
Elliott Hughesb708d162015-10-27 16:03:15 -0700361 LinePrinter line_printer_;
Elliott Hughesaa245492015-08-03 10:38:08 -0700362
Spencer Low351ecd12015-10-14 17:32:44 -0700363 bool SendQuit() {
364 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesaa245492015-08-03 10:38:08 -0700365 }
366
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800367 bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
368 if (!WriteFdExactly(fd, data, data_length)) {
369 if (errno == ECONNRESET) {
370 // Assume adbd told us why it was closing the connection, and
371 // try to read failure reason from adbd.
372 syncmsg msg;
373 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
374 Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
375 } else if (msg.status.id != ID_FAIL) {
376 Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
377 } else {
378 ReportCopyFailure(from, to, msg);
379 }
380 } else {
381 Error("%zu-byte write failed: %s", data_length, strerror(errno));
382 }
383 _exit(1);
384 }
385 return true;
386 }
387
Elliott Hughesb708d162015-10-27 16:03:15 -0700388 static uint64_t CurrentTimeMs() {
389 struct timeval tv;
390 gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
391 return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
Elliott Hughesaa245492015-08-03 10:38:08 -0700392 }
393};
394
Josh Gaocda6a2b2015-11-02 16:45:47 -0800395typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesaa245492015-08-03 10:38:08 -0700396
Josh Gaocda6a2b2015-11-02 16:45:47 -0800397static bool sync_ls(SyncConnection& sc, const char* path,
398 std::function<sync_ls_cb> func) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700399 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700400
401 while (true) {
402 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700403 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700404
405 if (msg.dent.id == ID_DONE) return true;
406 if (msg.dent.id != ID_DENT) return false;
407
Elliott Hughesf4465202015-08-24 14:27:03 -0700408 size_t len = msg.dent.namelen;
Elliott Hughesaa245492015-08-03 10:38:08 -0700409 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800410
Elliott Hughes5c742702015-07-30 17:42:01 -0700411 char buf[257];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700412 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800413 buf[len] = 0;
414
Josh Gaocda6a2b2015-11-02 16:45:47 -0800415 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800416 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800417}
418
Elliott Hughesaa245492015-08-03 10:38:08 -0700419static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
420 unsigned int* mode, unsigned int* size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800421 syncmsg msg;
Elliott Hughesaa245492015-08-03 10:38:08 -0700422 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
423 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800424 }
425
Elliott Hughesf4465202015-08-24 14:27:03 -0700426 if (timestamp) *timestamp = msg.stat.time;
427 if (mode) *mode = msg.stat.mode;
428 if (size) *size = msg.stat.size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800429
Elliott Hughesaa245492015-08-03 10:38:08 -0700430 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800431}
432
Elliott Hughesaa245492015-08-03 10:38:08 -0700433static bool sync_stat(SyncConnection& sc, const char* path,
434 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700435 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800436}
437
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700438static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesb708d162015-10-27 16:03:15 -0700439 unsigned mtime, mode_t mode)
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700440{
441 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
442
443 if (S_ISLNK(mode)) {
444#if !defined(_WIN32)
445 char buf[PATH_MAX];
446 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
447 if (data_length == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700448 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700449 return false;
450 }
451 buf[data_length++] = '\0';
452
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800453 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
454 return false;
455 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700456 return sc.CopyDone(lpath, rpath);
457#endif
458 }
459
460 if (!S_ISREG(mode)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700461 sc.Error("local file '%s' has unsupported mode: 0o%o", lpath, mode);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700462 return false;
463 }
464
465 struct stat st;
466 if (stat(lpath, &st) == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700467 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700468 return false;
469 }
470 if (st.st_size < SYNC_DATA_MAX) {
471 std::string data;
472 if (!android::base::ReadFileToString(lpath, &data)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700473 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700474 return false;
475 }
Elliott Hughescc65c3b2015-11-20 22:01:06 -0800476 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
477 data.data(), data.size())) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700478 return false;
479 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700480 } else {
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800481 if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700482 return false;
483 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700484 }
485 return sc.CopyDone(lpath, rpath);
486}
487
Elliott Hughesb708d162015-10-27 16:03:15 -0700488static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700489 unsigned size = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700490 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner76f2a932014-03-11 17:55:59 -0700491
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700492 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800493
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700494 adb_unlink(lpath);
Josh Gaof6e65e32015-11-17 14:08:20 -0800495 const std::string dirpath = adb_dirname(lpath);
496 if (!mkdirs(dirpath.c_str())) {
497 sc.Error("failed to create parent directory '%s': %s", dirpath.c_str(), strerror(errno));
Josh Gao45b6fc82015-11-04 14:51:23 -0800498 return false;
499 }
500
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700501 int lfd = adb_creat(lpath, 0644);
502 if (lfd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700503 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700504 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800505 }
506
Elliott Hughesb708d162015-10-27 16:03:15 -0700507 uint64_t bytes_copied = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700508 while (true) {
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700509 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700510 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700511 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700512 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700513 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800514 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800515
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700516 if (msg.data.id == ID_DONE) break;
517
518 if (msg.data.id != ID_DATA) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800519 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700520 adb_unlink(lpath);
521 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700522 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800523 }
524
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700525 if (msg.data.size > sc.max) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700526 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 -0800527 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700528 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700529 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800530 }
531
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700532 char buffer[SYNC_DATA_MAX];
533 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800534 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700535 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700536 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800537 }
538
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700539 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700540 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700541 adb_close(lfd);
542 adb_unlink(lpath);
543 return false;
544 }
545
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800546 sc.total_bytes_ += msg.data.size;
Mark Lindner76f2a932014-03-11 17:55:59 -0700547
Elliott Hughesb708d162015-10-27 16:03:15 -0700548 bytes_copied += msg.data.size;
549
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800550 sc.ReportProgress(rpath, bytes_copied, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800551 }
552
553 adb_close(lfd);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700554 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800555}
556
Elliott Hughesaa245492015-08-03 10:38:08 -0700557bool do_sync_ls(const char* path) {
558 SyncConnection sc;
559 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800560
Josh Gaocda6a2b2015-11-02 16:45:47 -0800561 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
562 const char* name) {
563 printf("%08x %08x %08x %s\n", mode, size, time, name);
564 });
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800565}
566
Elliott Hughesaa245492015-08-03 10:38:08 -0700567static bool IsDotOrDotDot(const char* name) {
568 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
569}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800570
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800571static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800572 const std::string& lpath,
573 const std::string& rpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800574 std::vector<copyinfo> dirlist;
Josh Gaod9731572015-11-03 15:23:03 -0800575 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
Elliott Hughesaa245492015-08-03 10:38:08 -0700576 if (!dir) {
Josh Gaod9731572015-11-03 15:23:03 -0800577 sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800578 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800579 }
580
Josh Gao65800962015-11-04 14:57:04 -0800581 bool empty_dir = true;
Elliott Hughesb708d162015-10-27 16:03:15 -0700582 dirent* de;
Elliott Hughesaa245492015-08-03 10:38:08 -0700583 while ((de = readdir(dir.get()))) {
Josh Gao65800962015-11-04 14:57:04 -0800584 if (IsDotOrDotDot(de->d_name)) {
585 continue;
586 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700587
Josh Gao65800962015-11-04 14:57:04 -0800588 empty_dir = false;
Josh Gaod9731572015-11-03 15:23:03 -0800589 std::string stat_path = lpath + de->d_name;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800590
Elliott Hughesaa245492015-08-03 10:38:08 -0700591 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800592 if (lstat(stat_path.c_str(), &st) == -1) {
Josh Gaod9731572015-11-03 15:23:03 -0800593 sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
594 strerror(errno));
Josh Gao12a2ae92015-11-07 15:27:26 -0800595 continue;
596 }
597
Josh Gaof2642242015-12-09 14:03:30 -0800598 copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
Josh Gao12a2ae92015-11-07 15:27:26 -0800599 if (S_ISDIR(st.st_mode)) {
600 dirlist.push_back(ci);
601 } else {
602 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
603 sc.Error("skipping special file '%s'", lpath.c_str());
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800604 ci.skip = true;
Josh Gao12a2ae92015-11-07 15:27:26 -0800605 } else {
606 ci.time = st.st_mtime;
607 ci.size = st.st_size;
Josh Gao12a2ae92015-11-07 15:27:26 -0800608 }
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800609 file_list->push_back(ci);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800610 }
611 }
612
Elliott Hughesaa245492015-08-03 10:38:08 -0700613 // Close this directory and recurse.
614 dir.reset();
Josh Gao65800962015-11-04 14:57:04 -0800615
616 // Add the current directory to the list if it was empty, to ensure that
617 // it gets created.
618 if (empty_dir) {
619 // TODO(b/25566053): Make pushing empty directories work.
620 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao21abf5a2015-11-07 17:18:44 -0800621 sc.Warning("skipping empty directory '%s'", lpath.c_str());
Josh Gaof2642242015-12-09 14:03:30 -0800622 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
Josh Gao65800962015-11-04 14:57:04 -0800623 ci.skip = true;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800624 file_list->push_back(ci);
Josh Gao65800962015-11-04 14:57:04 -0800625 return true;
626 }
627
Josh Gaocda6a2b2015-11-02 16:45:47 -0800628 for (const copyinfo& ci : dirlist) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800629 local_build_list(sc, file_list, ci.lpath, ci.rpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800630 }
631
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800632 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800633}
634
Josh Gaod9731572015-11-03 15:23:03 -0800635static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
636 std::string rpath, bool check_timestamps,
637 bool list_only) {
638 // Make sure that both directory paths end in a slash.
Josh Gao1a025302015-11-09 11:12:14 -0800639 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800640 ensure_trailing_separators(lpath, rpath);
Josh Gaod9731572015-11-03 15:23:03 -0800641
642 // Recursively build the list of files to copy.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800643 std::vector<copyinfo> file_list;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800644 int pushed = 0;
645 int skipped = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800646 if (!local_build_list(sc, &file_list, lpath, rpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700647 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800648 }
649
Elliott Hughesaa245492015-08-03 10:38:08 -0700650 if (check_timestamps) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800651 for (const copyinfo& ci : file_list) {
Josh Gao1a025302015-11-09 11:12:14 -0800652 if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
Josh Gaod9731572015-11-03 15:23:03 -0800653 return false;
654 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800655 }
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800656 for (copyinfo& ci : file_list) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800657 unsigned int timestamp, mode, size;
Josh Gaod9731572015-11-03 15:23:03 -0800658 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
659 return false;
660 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800661 if (size == ci.size) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800662 // For links, we cannot update the atime/mtime.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800663 if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
664 (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800665 ci.skip = true;
Elliott Hughesaa245492015-08-03 10:38:08 -0700666 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800667 }
668 }
669 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800670
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800671 sc.ComputeExpectedTotalBytes(file_list);
672
673 for (const copyinfo& ci : file_list) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800674 if (!ci.skip) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700675 if (list_only) {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800676 sc.Error("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
Elliott Hughesb708d162015-10-27 16:03:15 -0700677 } else {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800678 if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) {
Josh Gaod9731572015-11-03 15:23:03 -0800679 return false;
Elliott Hughesb708d162015-10-27 16:03:15 -0700680 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800681 }
682 pushed++;
683 } else {
684 skipped++;
685 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800686 }
687
Elliott Hughes77f539a2015-12-08 16:01:15 -0800688 sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s", rpath.c_str(),
Josh Gaod9731572015-11-03 15:23:03 -0800689 pushed, (pushed == 1) ? "" : "s", skipped,
690 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700691 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800692}
693
Josh Gao05786772015-10-30 16:57:19 -0700694bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700695 SyncConnection sc;
696 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800697
Josh Gao05786772015-10-30 16:57:19 -0700698 bool success = true;
Josh Gao12a2ae92015-11-07 15:27:26 -0800699 unsigned dst_mode;
700 if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false;
701 bool dst_exists = (dst_mode != 0);
Josh Gao07db1192015-11-07 15:38:19 -0800702 bool dst_isdir = S_ISDIR(dst_mode);
Josh Gao05786772015-10-30 16:57:19 -0700703
Josh Gao07db1192015-11-07 15:38:19 -0800704 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700705 if (srcs.size() > 1) {
706 sc.Error("target '%s' is not a directory", dst);
707 return false;
708 } else {
709 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -0800710
711 // A path that ends with a slash doesn't have to be a directory if
712 // it doesn't exist yet.
713 if (dst[dst_len - 1] == '/' && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -0700714 sc.Error("failed to access '%s': Not a directory", dst);
715 return false;
716 }
717 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700718 }
Josh Gao05786772015-10-30 16:57:19 -0700719
720 for (const char* src_path : srcs) {
721 const char* dst_path = dst;
722 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800723 if (stat(src_path, &st) == -1) {
Josh Gao05786772015-10-30 16:57:19 -0700724 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
725 success = false;
726 continue;
727 }
728
729 if (S_ISDIR(st.st_mode)) {
Josh Gao07db1192015-11-07 15:38:19 -0800730 std::string dst_dir = dst;
731
732 // If the destination path existed originally, the source directory
733 // should be copied as a child of the destination.
734 if (dst_exists) {
735 if (!dst_isdir) {
736 sc.Error("target '%s' is not a directory", dst);
737 return false;
738 }
739 // dst is a POSIX path, so we don't want to use the sysdeps
740 // helpers here.
741 if (dst_dir.back() != '/') {
742 dst_dir.push_back('/');
743 }
744 dst_dir.append(adb_basename(src_path));
745 }
746
747 success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(),
748 false, false);
Josh Gao05786772015-10-30 16:57:19 -0700749 continue;
750 }
751
752 std::string path_holder;
Josh Gao07db1192015-11-07 15:38:19 -0800753 if (dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700754 // If we're copying a local file to a remote directory,
755 // we really want to copy to remote_dir + "/" + local_filename.
Josh Gao323899b2016-02-03 14:55:24 -0800756 path_holder = dst_path;
757 if (path_holder.back() != '/') {
758 path_holder.push_back('/');
759 }
760 path_holder += adb_basename(src_path);
Josh Gao05786772015-10-30 16:57:19 -0700761 dst_path = path_holder.c_str();
762 }
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800763 sc.SetExpectedTotalBytes(st.st_size);
Josh Gao05786772015-10-30 16:57:19 -0700764 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
765 }
766
Josh Gao05786772015-10-30 16:57:19 -0700767 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800768}
769
Josh Gaof2642242015-12-09 14:03:30 -0800770static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) {
771 unsigned mode;
772 std::string dir_path = rpath;
773 dir_path.push_back('/');
774 if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) {
775 sc.Error("failed to stat remote symlink '%s'", dir_path.c_str());
776 return false;
777 }
778 return S_ISDIR(mode);
779}
780
Josh Gaocda6a2b2015-11-02 16:45:47 -0800781static bool remote_build_list(SyncConnection& sc,
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800782 std::vector<copyinfo>* file_list,
Josh Gaod9731572015-11-03 15:23:03 -0800783 const std::string& rpath,
784 const std::string& lpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800785 std::vector<copyinfo> dirlist;
Josh Gaof2642242015-12-09 14:03:30 -0800786 std::vector<copyinfo> linklist;
Josh Gao65800962015-11-04 14:57:04 -0800787 bool empty_dir = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800788
Elliott Hughesaa245492015-08-03 10:38:08 -0700789 // Put the files/dirs in rpath on the lists.
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800790 auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
Josh Gao65800962015-11-04 14:57:04 -0800791 if (IsDotOrDotDot(name)) {
792 return;
793 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800794
Josh Gao65800962015-11-04 14:57:04 -0800795 // We found a child that isn't '.' or '..'.
796 empty_dir = false;
797
Josh Gaof2642242015-12-09 14:03:30 -0800798 copyinfo ci(lpath, rpath, name, mode);
Josh Gao65800962015-11-04 14:57:04 -0800799 if (S_ISDIR(mode)) {
800 dirlist.push_back(ci);
Josh Gaof2642242015-12-09 14:03:30 -0800801 } else if (S_ISLNK(mode)) {
802 linklist.push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -0800803 } else {
Josh Gaof2642242015-12-09 14:03:30 -0800804 ci.time = time;
805 ci.size = size;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800806 file_list->push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -0800807 }
808 };
809
Josh Gaod9731572015-11-03 15:23:03 -0800810 if (!sync_ls(sc, rpath.c_str(), callback)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700811 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800812 }
813
Josh Gaof2642242015-12-09 14:03:30 -0800814 // Add the current directory to the list if it was empty, to ensure that it gets created.
Josh Gao65800962015-11-04 14:57:04 -0800815 if (empty_dir) {
Josh Gaof2642242015-12-09 14:03:30 -0800816 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(rpath), S_IFDIR);
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800817 file_list->push_back(ci);
Josh Gao65800962015-11-04 14:57:04 -0800818 return true;
819 }
820
Josh Gaof2642242015-12-09 14:03:30 -0800821 // Check each symlink we found to see whether it's a file or directory.
822 for (copyinfo& link_ci : linklist) {
823 if (remote_symlink_isdir(sc, link_ci.rpath)) {
824 dirlist.emplace_back(std::move(link_ci));
825 } else {
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800826 file_list->emplace_back(std::move(link_ci));
Josh Gaof2642242015-12-09 14:03:30 -0800827 }
828 }
829
Elliott Hughesaa245492015-08-03 10:38:08 -0700830 // Recurse into each directory we found.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800831 while (!dirlist.empty()) {
832 copyinfo current = dirlist.back();
833 dirlist.pop_back();
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800834 if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700835 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800836 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800837 }
838
Elliott Hughesaa245492015-08-03 10:38:08 -0700839 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800840}
841
Josh Gao1a025302015-11-09 11:12:14 -0800842static int set_time_and_mode(const std::string& lpath, time_t time,
843 unsigned int mode) {
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700844 struct utimbuf times = { time, time };
Josh Gao1a025302015-11-09 11:12:14 -0800845 int r1 = utime(lpath.c_str(), &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700846
847 /* use umask for permissions */
Josh Gaocda6a2b2015-11-02 16:45:47 -0800848 mode_t mask = umask(0000);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700849 umask(mask);
Josh Gao1a025302015-11-09 11:12:14 -0800850 int r2 = chmod(lpath.c_str(), mode & ~mask);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700851
Spencer Low363af562015-11-07 18:51:54 -0800852 return r1 ? r1 : r2;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700853}
854
Josh Gaod9731572015-11-03 15:23:03 -0800855static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
856 std::string lpath, bool copy_attrs) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700857 // Make sure that both directory paths end in a slash.
Josh Gao12a2ae92015-11-07 15:27:26 -0800858 // Both paths are known to be nonempty, so we don't need to check.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800859 ensure_trailing_separators(lpath, rpath);
Riley Andrews4d04d242014-12-12 13:12:36 -0800860
Elliott Hughesaa245492015-08-03 10:38:08 -0700861 // Recursively build the list of files to copy.
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800862 sc.Printf("pull: building file list...");
863 std::vector<copyinfo> file_list;
864 if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800865 return false;
866 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700867
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800868 sc.ComputeExpectedTotalBytes(file_list);
869
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800870 int pulled = 0;
871 int skipped = 0;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800872 for (const copyinfo &ci : file_list) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800873 if (!ci.skip) {
Josh Gao65800962015-11-04 14:57:04 -0800874 if (S_ISDIR(ci.mode)) {
875 // Entry is for an empty directory, create it and continue.
876 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao1a025302015-11-09 11:12:14 -0800877 if (!mkdirs(ci.lpath)) {
Josh Gao65800962015-11-04 14:57:04 -0800878 sc.Error("failed to create directory '%s': %s",
Josh Gao1a025302015-11-09 11:12:14 -0800879 ci.lpath.c_str(), strerror(errno));
Josh Gao65800962015-11-04 14:57:04 -0800880 return false;
881 }
882 pulled++;
883 continue;
884 }
885
Josh Gao1a025302015-11-09 11:12:14 -0800886 if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700887 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800888 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700889
Josh Gao1a025302015-11-09 11:12:14 -0800890 if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700891 return false;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700892 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800893 pulled++;
894 } else {
895 skipped++;
896 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800897 }
898
Elliott Hughes77f539a2015-12-08 16:01:15 -0800899 sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s", rpath.c_str(),
Josh Gaod9731572015-11-03 15:23:03 -0800900 pulled, (pulled == 1) ? "" : "s", skipped,
901 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700902 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800903}
904
Josh Gao05786772015-10-30 16:57:19 -0700905bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
906 bool copy_attrs) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700907 SyncConnection sc;
908 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800909
Josh Gao05786772015-10-30 16:57:19 -0700910 bool success = true;
Josh Gao05786772015-10-30 16:57:19 -0700911 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800912 bool dst_exists = true;
913
914 if (stat(dst, &st) == -1) {
915 dst_exists = false;
916
917 // If we're only pulling one path, the destination path might point to
Josh Gao05786772015-10-30 16:57:19 -0700918 // a path that doesn't exist yet.
Josh Gao12a2ae92015-11-07 15:27:26 -0800919 if (srcs.size() == 1 && errno == ENOENT) {
920 // However, its parent must exist.
921 struct stat parent_st;
922 if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
923 sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
924 return false;
925 }
926 } else {
927 sc.Error("failed to access '%s': %s", dst, strerror(errno));
Josh Gao05786772015-10-30 16:57:19 -0700928 return false;
929 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800930 }
931
Josh Gao07db1192015-11-07 15:38:19 -0800932 bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
933 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700934 if (srcs.size() > 1) {
935 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700936 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800937 } else {
Josh Gao05786772015-10-30 16:57:19 -0700938 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -0800939
940 // A path that ends with a slash doesn't have to be a directory if
941 // it doesn't exist yet.
Josh Gao1a025302015-11-09 11:12:14 -0800942 if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -0700943 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700944 return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700945 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800946 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800947 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700948
Josh Gao05786772015-10-30 16:57:19 -0700949 for (const char* src_path : srcs) {
950 const char* dst_path = dst;
Elliott Hughesa00e6ef2015-12-17 17:05:29 -0800951 unsigned src_mode, src_time, src_size;
952 if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) {
Josh Gaof2642242015-12-09 14:03:30 -0800953 sc.Error("failed to stat remote object '%s'", src_path);
Josh Gao12a2ae92015-11-07 15:27:26 -0800954 return false;
955 }
956 if (src_mode == 0) {
Josh Gao05786772015-10-30 16:57:19 -0700957 sc.Error("remote object '%s' does not exist", src_path);
958 success = false;
959 continue;
960 }
961
Josh Gaof2642242015-12-09 14:03:30 -0800962 bool src_isdir = S_ISDIR(src_mode);
963 if (S_ISLNK(src_mode)) {
964 src_isdir = remote_symlink_isdir(sc, src_path);
965 }
966
967 if ((src_mode & (S_IFREG | S_IFDIR | S_IFBLK | S_IFCHR)) == 0) {
968 sc.Error("skipping remote object '%s' (mode = 0o%o)", src_path, src_mode);
969 continue;
970 }
971
972 if (src_isdir) {
Josh Gao07db1192015-11-07 15:38:19 -0800973 std::string dst_dir = dst;
974
975 // If the destination path existed originally, the source directory
976 // should be copied as a child of the destination.
977 if (dst_exists) {
978 if (!dst_isdir) {
979 sc.Error("target '%s' is not a directory", dst);
980 return false;
981 }
982 if (!adb_is_separator(dst_dir.back())) {
983 dst_dir.push_back(OS_PATH_SEPARATOR);
984 }
985 dst_dir.append(adb_basename(src_path));
986 }
987
Josh Gaof2642242015-12-09 14:03:30 -0800988 success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
Josh Gao05786772015-10-30 16:57:19 -0700989 continue;
990 } else {
Josh Gaof2642242015-12-09 14:03:30 -0800991 std::string path_holder;
992 if (dst_isdir) {
993 // If we're copying a remote file to a local directory, we
994 // really want to copy to local_dir + OS_PATH_SEPARATOR +
995 // basename(remote).
996 path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
997 adb_basename(src_path).c_str());
998 dst_path = path_holder.c_str();
999 }
1000
Elliott Hughesa00e6ef2015-12-17 17:05:29 -08001001 sc.SetExpectedTotalBytes(src_size);
Josh Gaof2642242015-12-09 14:03:30 -08001002 if (!sync_recv(sc, src_path, dst_path)) {
1003 success = false;
1004 continue;
1005 }
1006
1007 if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) {
1008 success = false;
1009 continue;
1010 }
Josh Gao05786772015-10-30 16:57:19 -07001011 }
1012 }
1013
Josh Gao05786772015-10-30 16:57:19 -07001014 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001015}
1016
Elliott Hughesaa245492015-08-03 10:38:08 -07001017bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesaa245492015-08-03 10:38:08 -07001018 SyncConnection sc;
1019 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001020
Josh Gaod9731572015-11-03 15:23:03 -08001021 return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001022}