blob: c7eeea7e64dcd53b095e89f036820320efad8dc9 [file] [log] [blame]
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Dan Albertb302d122015-02-24 15:51:19 -080017#include <dirent.h>
18#include <errno.h>
Spencer Low803451e2015-05-13 00:02:55 -070019#include <inttypes.h>
Dan Albertb302d122015-02-24 15:51:19 -080020#include <limits.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080024#include <sys/stat.h>
25#include <sys/time.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080026#include <sys/types.h>
Dan Albertb302d122015-02-24 15:51:19 -080027#include <time.h>
Elliott Hughesdde00be2015-09-27 12:55:37 -070028#include <unistd.h>
Greg Hackmann8b689142014-05-06 08:48:18 -070029#include <utime.h>
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080030
Josh Gao204d21e2015-11-02 16:45:47 -080031#include <functional>
Elliott Hughes4e7848d2015-08-24 14:49:43 -070032#include <memory>
Elliott Hughes6c73bfc2015-10-27 13:40:35 -070033#include <vector>
Elliott Hughes4e7848d2015-08-24 14:49:43 -070034
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080035#include "sysdeps.h"
Dan Albertb302d122015-02-24 15:51:19 -080036
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080037#include "adb.h"
38#include "adb_client.h"
Dan Albert66a91b02015-02-24 21:26:58 -080039#include "adb_io.h"
Alex Valléee9163152015-05-06 17:22:25 -040040#include "adb_utils.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080041#include "file_sync_service.h"
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070042#include "line_printer.h"
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080043
Elliott Hughesf55ead92015-12-04 22:00:26 -080044#include <android-base/file.h>
45#include <android-base/strings.h>
46#include <android-base/stringprintf.h>
Elliott Hughesd189cfb2015-07-30 17:42:01 -070047
Elliott Hughesb628cb12015-08-03 10:38:08 -070048struct syncsendbuf {
49 unsigned id;
50 unsigned size;
51 char data[SYNC_DATA_MAX];
52};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -080053
Elliott Hughesb628cb12015-08-03 10:38:08 -070054class SyncConnection {
55 public:
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070056 SyncConnection() : total_bytes(0), start_time_ms_(CurrentTimeMs()) {
Elliott Hughesb628cb12015-08-03 10:38:08 -070057 max = SYNC_DATA_MAX; // TODO: decide at runtime.
58
59 std::string error;
60 fd = adb_connect("sync:", &error);
61 if (fd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070062 Error("connect failed: %s", error.c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -070063 }
64 }
65
66 ~SyncConnection() {
67 if (!IsValid()) return;
68
Spencer Lowcc4a4b12015-10-14 17:32:44 -070069 if (SendQuit()) {
70 // We sent a quit command, so the server should be doing orderly
71 // shutdown soon. But if we encountered an error while we were using
72 // the connection, the server might still be sending data (before
73 // doing orderly shutdown), in which case we won't wait for all of
74 // the data nor the coming orderly shutdown. In the common success
75 // case, this will wait for the server to do orderly shutdown.
76 ReadOrderlyShutdown(fd);
77 }
Elliott Hughesb628cb12015-08-03 10:38:08 -070078 adb_close(fd);
79 }
80
81 bool IsValid() { return fd >= 0; }
82
Elliott Hughesdde00be2015-09-27 12:55:37 -070083 bool SendRequest(int id, const char* path_and_mode) {
84 size_t path_length = strlen(path_and_mode);
85 if (path_length > 1024) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -070086 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -070087 errno = ENAMETOOLONG;
88 return false;
89 }
90
91 // Sending header and payload in a single write makes a noticeable
92 // difference to "adb sync" performance.
Elliott Hughes6c73bfc2015-10-27 13:40:35 -070093 std::vector<char> buf(sizeof(SyncRequest) + path_length);
94 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesdde00be2015-09-27 12:55:37 -070095 req->id = id;
96 req->path_length = path_length;
97 char* data = reinterpret_cast<char*>(req + 1);
98 memcpy(data, path_and_mode, path_length);
99
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700100 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesdde00be2015-09-27 12:55:37 -0700101 }
102
103 // Sending header, payload, and footer in a single write makes a huge
104 // difference to "adb sync" performance.
105 bool SendSmallFile(const char* path_and_mode,
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800106 const char* lpath, const char* rpath,
Elliott Hughes7275d802015-11-20 17:35:17 -0800107 unsigned mtime,
108 const char* data, size_t data_length) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700109 Print(rpath);
110
Elliott Hughesdde00be2015-09-27 12:55:37 -0700111 size_t path_length = strlen(path_and_mode);
112 if (path_length > 1024) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700113 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700114 errno = ENAMETOOLONG;
115 return false;
116 }
117
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700118 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughes7275d802015-11-20 17:35:17 -0800119 sizeof(SyncRequest) + data_length +
120 sizeof(SyncRequest));
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700121 char* p = &buf[0];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700122
123 SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
124 req_send->id = ID_SEND;
125 req_send->path_length = path_length;
126 p += sizeof(SyncRequest);
127 memcpy(p, path_and_mode, path_length);
128 p += path_length;
129
130 SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
131 req_data->id = ID_DATA;
132 req_data->path_length = data_length;
133 p += sizeof(SyncRequest);
134 memcpy(p, data, data_length);
135 p += data_length;
136
137 SyncRequest* req_done = reinterpret_cast<SyncRequest*>(p);
138 req_done->id = ID_DONE;
139 req_done->path_length = mtime;
140 p += sizeof(SyncRequest);
141
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800142 WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700143 total_bytes += data_length;
144 return true;
145 }
146
Elliott Hughes7275d802015-11-20 17:35:17 -0800147 bool SendLargeFile(const char* path_and_mode,
148 const char* lpath, const char* rpath,
149 unsigned mtime) {
150 if (!SendRequest(ID_SEND, path_and_mode)) {
151 Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
152 return false;
153 }
154
155 struct stat st;
156 if (stat(lpath, &st) == -1) {
157 Error("cannot stat '%s': %s", lpath, strerror(errno));
158 return false;
159 }
160
161 uint64_t total_size = st.st_size;
162 uint64_t bytes_copied = 0;
163
164 int lfd = adb_open(lpath, O_RDONLY);
165 if (lfd < 0) {
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800166 Error("opening '%s' locally failed: %s", lpath, strerror(errno));
Elliott Hughes7275d802015-11-20 17:35:17 -0800167 return false;
168 }
169
170 syncsendbuf sbuf;
171 sbuf.id = ID_DATA;
172 while (true) {
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800173 int bytes_read = adb_read(lfd, sbuf.data, max);
174 if (bytes_read == -1) {
175 Error("reading '%s' locally failed: %s", lpath, strerror(errno));
176 adb_close(lfd);
177 return false;
178 } else if (bytes_read == 0) {
Elliott Hughes7275d802015-11-20 17:35:17 -0800179 break;
180 }
181
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800182 sbuf.size = bytes_read;
183 WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
Elliott Hughes7275d802015-11-20 17:35:17 -0800184
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800185 total_bytes += bytes_read;
186 bytes_copied += bytes_read;
Elliott Hughes7275d802015-11-20 17:35:17 -0800187
Josh Gao9b523642015-11-30 10:53:22 -0800188 if (total_size == 0) {
189 // This case can happen if we're racing against something that wrote to the file
190 // between our stat and our read, or if we're reading a magic file that lies about
191 // its size.
192 Printf("%s: ?%%", rpath);
193 } else {
194 int percentage = static_cast<int>(bytes_copied * 100 / total_size);
195 Printf("%s: %d%%", rpath, percentage);
196 }
Elliott Hughes7275d802015-11-20 17:35:17 -0800197 }
198
199 adb_close(lfd);
200
201 syncmsg msg;
202 msg.data.id = ID_DONE;
203 msg.data.size = mtime;
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800204 return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
Elliott Hughes7275d802015-11-20 17:35:17 -0800205 }
206
Elliott Hughesdde00be2015-09-27 12:55:37 -0700207 bool CopyDone(const char* from, const char* to) {
208 syncmsg msg;
209 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700210 Error("failed to copy '%s' to '%s': no ID_DONE: %s", from, to, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700211 return false;
212 }
213 if (msg.status.id == ID_OKAY) {
214 return true;
215 }
216 if (msg.status.id != ID_FAIL) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700217 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700218 return false;
219 }
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700220 return ReportCopyFailure(from, to, msg);
221 }
222
223 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700224 std::vector<char> buf(msg.status.msglen + 1);
225 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700226 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
227 from, to, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700228 return false;
229 }
Elliott Hughes6c73bfc2015-10-27 13:40:35 -0700230 buf[msg.status.msglen] = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700231 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700232 return false;
233 }
234
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700235 std::string TransferRate() {
236 uint64_t ms = CurrentTimeMs() - start_time_ms_;
237 if (total_bytes == 0 || ms == 0) return "";
238
239 double s = static_cast<double>(ms) / 1000LL;
240 double rate = (static_cast<double>(total_bytes) / s) / (1024*1024);
241 return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
242 rate, total_bytes, s);
243 }
244
245 void Print(const std::string& s) {
246 // TODO: we actually don't want ELIDE; we want "ELIDE if smart, FULL if dumb".
247 line_printer_.Print(s, LinePrinter::ELIDE);
248 }
249
Josh Gaocbf485f2015-11-02 17:15:57 -0800250 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
251 std::string s;
252 va_list ap;
253 va_start(ap, fmt);
254 android::base::StringAppendV(&s, fmt, ap);
255 va_end(ap);
256
257 Print(s);
258 }
259
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700260 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
261 std::string s = "adb: error: ";
262
263 va_list ap;
264 va_start(ap, fmt);
265 android::base::StringAppendV(&s, fmt, ap);
266 va_end(ap);
267
268 line_printer_.Print(s, LinePrinter::FULL);
269 }
270
Josh Gaoa544cc62015-11-07 17:18:44 -0800271 void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
272 std::string s = "adb: warning: ";
273
274 va_list ap;
275 va_start(ap, fmt);
276 android::base::StringAppendV(&s, fmt, ap);
277 va_end(ap);
278
279 line_printer_.Print(s, LinePrinter::FULL);
280 }
281
Elliott Hughesb628cb12015-08-03 10:38:08 -0700282 uint64_t total_bytes;
283
284 // TODO: add a char[max] buffer here, to replace syncsendbuf...
285 int fd;
286 size_t max;
287
288 private:
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700289 uint64_t start_time_ms_;
290
291 LinePrinter line_printer_;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700292
Spencer Lowcc4a4b12015-10-14 17:32:44 -0700293 bool SendQuit() {
294 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesb628cb12015-08-03 10:38:08 -0700295 }
296
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800297 bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
298 if (!WriteFdExactly(fd, data, data_length)) {
299 if (errno == ECONNRESET) {
300 // Assume adbd told us why it was closing the connection, and
301 // try to read failure reason from adbd.
302 syncmsg msg;
303 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
304 Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
305 } else if (msg.status.id != ID_FAIL) {
306 Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
307 } else {
308 ReportCopyFailure(from, to, msg);
309 }
310 } else {
311 Error("%zu-byte write failed: %s", data_length, strerror(errno));
312 }
313 _exit(1);
314 }
315 return true;
316 }
317
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700318 static uint64_t CurrentTimeMs() {
319 struct timeval tv;
320 gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
321 return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700322 }
323};
324
Josh Gao204d21e2015-11-02 16:45:47 -0800325typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700326
Josh Gao204d21e2015-11-02 16:45:47 -0800327static bool sync_ls(SyncConnection& sc, const char* path,
328 std::function<sync_ls_cb> func) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700329 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700330
331 while (true) {
332 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700333 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700334
335 if (msg.dent.id == ID_DONE) return true;
336 if (msg.dent.id != ID_DENT) return false;
337
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700338 size_t len = msg.dent.namelen;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700339 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800340
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700341 char buf[257];
Elliott Hughesdde00be2015-09-27 12:55:37 -0700342 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800343 buf[len] = 0;
344
Josh Gao204d21e2015-11-02 16:45:47 -0800345 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800346 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800347}
348
Elliott Hughesb628cb12015-08-03 10:38:08 -0700349static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
350 unsigned int* mode, unsigned int* size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800351 syncmsg msg;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700352 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
353 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800354 }
355
Elliott Hughes9e8e3552015-08-24 14:27:03 -0700356 if (timestamp) *timestamp = msg.stat.time;
357 if (mode) *mode = msg.stat.mode;
358 if (size) *size = msg.stat.size;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800359
Elliott Hughesb628cb12015-08-03 10:38:08 -0700360 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800361}
362
Elliott Hughesb628cb12015-08-03 10:38:08 -0700363static bool sync_stat(SyncConnection& sc, const char* path,
364 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesdde00be2015-09-27 12:55:37 -0700365 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800366}
367
Elliott Hughesdde00be2015-09-27 12:55:37 -0700368static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700369 unsigned mtime, mode_t mode)
Elliott Hughesdde00be2015-09-27 12:55:37 -0700370{
371 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
372
373 if (S_ISLNK(mode)) {
374#if !defined(_WIN32)
375 char buf[PATH_MAX];
376 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
377 if (data_length == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700378 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700379 return false;
380 }
381 buf[data_length++] = '\0';
382
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800383 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
384 return false;
385 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700386 return sc.CopyDone(lpath, rpath);
387#endif
388 }
389
390 if (!S_ISREG(mode)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700391 sc.Error("local file '%s' has unsupported mode: 0o%o", lpath, mode);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700392 return false;
393 }
394
395 struct stat st;
396 if (stat(lpath, &st) == -1) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700397 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700398 return false;
399 }
400 if (st.st_size < SYNC_DATA_MAX) {
401 std::string data;
402 if (!android::base::ReadFileToString(lpath, &data)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700403 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesdde00be2015-09-27 12:55:37 -0700404 return false;
405 }
Elliott Hughes54e3efe2015-11-20 22:01:06 -0800406 if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
407 data.data(), data.size())) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700408 return false;
409 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700410 } else {
Elliott Hughes7275d802015-11-20 17:35:17 -0800411 if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700412 return false;
413 }
Elliott Hughesdde00be2015-09-27 12:55:37 -0700414 }
415 return sc.CopyDone(lpath, rpath);
416}
417
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700418static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
419 sc.Print(rpath);
420
Elliott Hughesb628cb12015-08-03 10:38:08 -0700421 unsigned size = 0;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700422 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700423
Elliott Hughesdde00be2015-09-27 12:55:37 -0700424 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800425
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700426 adb_unlink(lpath);
Josh Gaoe3a12162015-11-17 14:08:20 -0800427 const std::string dirpath = adb_dirname(lpath);
428 if (!mkdirs(dirpath.c_str())) {
429 sc.Error("failed to create parent directory '%s': %s", dirpath.c_str(), strerror(errno));
Josh Gaofe1a6122015-11-04 14:51:23 -0800430 return false;
431 }
432
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700433 int lfd = adb_creat(lpath, 0644);
434 if (lfd < 0) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700435 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700436 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800437 }
438
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700439 uint64_t bytes_copied = 0;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700440 while (true) {
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700441 syncmsg msg;
Elliott Hughesdde00be2015-09-27 12:55:37 -0700442 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowc1a31332015-08-28 01:07:30 -0700443 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700444 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700445 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800446 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800447
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700448 if (msg.data.id == ID_DONE) break;
449
450 if (msg.data.id != ID_DATA) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800451 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700452 adb_unlink(lpath);
453 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700454 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800455 }
456
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700457 if (msg.data.size > sc.max) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700458 sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800459 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700460 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700461 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800462 }
463
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700464 char buffer[SYNC_DATA_MAX];
465 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800466 adb_close(lfd);
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700467 adb_unlink(lpath);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700468 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800469 }
470
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700471 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700472 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughese4ed32f2015-10-23 21:06:11 -0700473 adb_close(lfd);
474 adb_unlink(lpath);
475 return false;
476 }
477
478 sc.total_bytes += msg.data.size;
Mark Lindner9f9d1452014-03-11 17:55:59 -0700479
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700480 bytes_copied += msg.data.size;
481
Josh Gao9b523642015-11-30 10:53:22 -0800482 if (size == 0) {
483 // This case can happen if we're racing against something that wrote to the file between
484 // our stat and our read, or if we're reading a magic file that lies about its size.
485 sc.Printf("%s: ?%%", rpath);
486 } else {
487 int percentage = static_cast<int>(bytes_copied * 100 / size);
488 sc.Printf("%s: %d%%", rpath, percentage);
489 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800490 }
491
492 adb_close(lfd);
Elliott Hughesdde00be2015-09-27 12:55:37 -0700493 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800494}
495
Elliott Hughesb628cb12015-08-03 10:38:08 -0700496bool do_sync_ls(const char* path) {
497 SyncConnection sc;
498 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800499
Josh Gao204d21e2015-11-02 16:45:47 -0800500 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
501 const char* name) {
502 printf("%08x %08x %08x %s\n", mode, size, time, name);
503 });
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800504}
505
Josh Gaoa3b6a062015-11-09 11:12:14 -0800506static void ensure_trailing_separator(std::string& lpath, std::string& rpath) {
507 if (!adb_is_separator(lpath.back())) {
508 lpath.push_back(OS_PATH_SEPARATOR);
509 }
510 if (rpath.back() != '/') {
511 rpath.push_back('/');
512 }
513}
514
Josh Gaod9a2fd62015-12-09 14:03:30 -0800515struct copyinfo {
516 std::string lpath;
517 std::string rpath;
518 unsigned int time = 0;
519 unsigned int mode;
520 uint64_t size = 0;
521 bool skip = false;
Josh Gaoa5cea712015-11-07 15:27:26 -0800522
Josh Gaod9a2fd62015-12-09 14:03:30 -0800523 copyinfo(const std::string& lpath, const std::string& rpath, const std::string& name,
524 unsigned int mode)
525 : lpath(lpath), rpath(rpath), mode(mode) {
526 ensure_trailing_separator(this->lpath, this->rpath);
527 this->lpath.append(name);
528 this->rpath.append(name);
529
530 if (S_ISDIR(mode)) {
531 ensure_trailing_separator(this->lpath, this->rpath);
532 }
Josh Gaod20cf382015-11-03 15:23:03 -0800533 }
Josh Gaod9a2fd62015-12-09 14:03:30 -0800534};
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800535
Elliott Hughesb628cb12015-08-03 10:38:08 -0700536static bool IsDotOrDotDot(const char* name) {
537 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
538}
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800539
Josh Gao8efa6462015-11-03 15:26:38 -0800540static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* filelist,
541 const std::string& lpath,
542 const std::string& rpath) {
Josh Gao204d21e2015-11-02 16:45:47 -0800543 std::vector<copyinfo> dirlist;
Josh Gaod20cf382015-11-03 15:23:03 -0800544 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700545 if (!dir) {
Josh Gaod20cf382015-11-03 15:23:03 -0800546 sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
Josh Gao8efa6462015-11-03 15:26:38 -0800547 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800548 }
549
Josh Gaoa90563e2015-11-04 14:57:04 -0800550 bool empty_dir = true;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700551 dirent* de;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700552 while ((de = readdir(dir.get()))) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800553 if (IsDotOrDotDot(de->d_name)) {
554 continue;
555 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700556
Josh Gaoa90563e2015-11-04 14:57:04 -0800557 empty_dir = false;
Josh Gaod20cf382015-11-03 15:23:03 -0800558 std::string stat_path = lpath + de->d_name;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800559
Elliott Hughesb628cb12015-08-03 10:38:08 -0700560 struct stat st;
Josh Gaoa5cea712015-11-07 15:27:26 -0800561 if (lstat(stat_path.c_str(), &st) == -1) {
Josh Gaod20cf382015-11-03 15:23:03 -0800562 sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
563 strerror(errno));
Josh Gaoa5cea712015-11-07 15:27:26 -0800564 continue;
565 }
566
Josh Gaod9a2fd62015-12-09 14:03:30 -0800567 copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
Josh Gaoa5cea712015-11-07 15:27:26 -0800568 if (S_ISDIR(st.st_mode)) {
569 dirlist.push_back(ci);
570 } else {
571 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
572 sc.Error("skipping special file '%s'", lpath.c_str());
Josh Gaob3cab932015-11-30 10:21:25 -0800573 ci.skip = true;
Josh Gaoa5cea712015-11-07 15:27:26 -0800574 } else {
575 ci.time = st.st_mtime;
576 ci.size = st.st_size;
Josh Gaoa5cea712015-11-07 15:27:26 -0800577 }
Josh Gaob3cab932015-11-30 10:21:25 -0800578 filelist->push_back(ci);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800579 }
580 }
581
Elliott Hughesb628cb12015-08-03 10:38:08 -0700582 // Close this directory and recurse.
583 dir.reset();
Josh Gaoa90563e2015-11-04 14:57:04 -0800584
585 // Add the current directory to the list if it was empty, to ensure that
586 // it gets created.
587 if (empty_dir) {
588 // TODO(b/25566053): Make pushing empty directories work.
589 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gaoa544cc62015-11-07 17:18:44 -0800590 sc.Warning("skipping empty directory '%s'", lpath.c_str());
Josh Gaod9a2fd62015-12-09 14:03:30 -0800591 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
Josh Gaoa90563e2015-11-04 14:57:04 -0800592 ci.skip = true;
593 filelist->push_back(ci);
594 return true;
595 }
596
Josh Gao204d21e2015-11-02 16:45:47 -0800597 for (const copyinfo& ci : dirlist) {
Josh Gaoa3b6a062015-11-09 11:12:14 -0800598 local_build_list(sc, filelist, ci.lpath, ci.rpath);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800599 }
600
Josh Gao8efa6462015-11-03 15:26:38 -0800601 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800602}
603
Josh Gaod20cf382015-11-03 15:23:03 -0800604static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
605 std::string rpath, bool check_timestamps,
606 bool list_only) {
607 // Make sure that both directory paths end in a slash.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800608 // Both paths are known to be nonempty, so we don't need to check.
609 ensure_trailing_separator(lpath, rpath);
Josh Gaod20cf382015-11-03 15:23:03 -0800610
611 // Recursively build the list of files to copy.
Josh Gao204d21e2015-11-02 16:45:47 -0800612 std::vector<copyinfo> filelist;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800613 int pushed = 0;
614 int skipped = 0;
Josh Gao8efa6462015-11-03 15:26:38 -0800615 if (!local_build_list(sc, &filelist, lpath, rpath)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700616 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800617 }
618
Elliott Hughesb628cb12015-08-03 10:38:08 -0700619 if (check_timestamps) {
Josh Gao204d21e2015-11-02 16:45:47 -0800620 for (const copyinfo& ci : filelist) {
Josh Gaoa3b6a062015-11-09 11:12:14 -0800621 if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
Josh Gaod20cf382015-11-03 15:23:03 -0800622 return false;
623 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800624 }
Josh Gao204d21e2015-11-02 16:45:47 -0800625 for (copyinfo& ci : filelist) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800626 unsigned int timestamp, mode, size;
Josh Gaod20cf382015-11-03 15:23:03 -0800627 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
628 return false;
629 }
Josh Gao204d21e2015-11-02 16:45:47 -0800630 if (size == ci.size) {
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800631 /* for links, we cannot update the atime/mtime */
Josh Gao204d21e2015-11-02 16:45:47 -0800632 if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
633 (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
Josh Gaocb094c62015-11-03 14:44:04 -0800634 ci.skip = true;
Elliott Hughesb628cb12015-08-03 10:38:08 -0700635 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800636 }
637 }
638 }
Josh Gao204d21e2015-11-02 16:45:47 -0800639
640 for (const copyinfo& ci : filelist) {
Josh Gaocb094c62015-11-03 14:44:04 -0800641 if (!ci.skip) {
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700642 if (list_only) {
Josh Gaoa3b6a062015-11-09 11:12:14 -0800643 sc.Error("would push: %s -> %s", ci.lpath.c_str(),
644 ci.rpath.c_str());
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700645 } else {
Josh Gaoa3b6a062015-11-09 11:12:14 -0800646 if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time,
Josh Gaod20cf382015-11-03 15:23:03 -0800647 ci.mode)) {
648 return false;
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700649 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800650 }
651 pushed++;
652 } else {
653 skipped++;
654 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800655 }
656
Josh Gaod20cf382015-11-03 15:23:03 -0800657 sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath.c_str(),
658 pushed, (pushed == 1) ? "" : "s", skipped,
659 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -0700660 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800661}
662
Josh Gao5d093b22015-10-30 16:57:19 -0700663bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700664 SyncConnection sc;
665 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800666
Josh Gao5d093b22015-10-30 16:57:19 -0700667 bool success = true;
Josh Gaoa5cea712015-11-07 15:27:26 -0800668 unsigned dst_mode;
669 if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false;
670 bool dst_exists = (dst_mode != 0);
Josh Gao8acf06c2015-11-07 15:38:19 -0800671 bool dst_isdir = S_ISDIR(dst_mode);
Josh Gao5d093b22015-10-30 16:57:19 -0700672
Josh Gao8acf06c2015-11-07 15:38:19 -0800673 if (!dst_isdir) {
Josh Gao5d093b22015-10-30 16:57:19 -0700674 if (srcs.size() > 1) {
675 sc.Error("target '%s' is not a directory", dst);
676 return false;
677 } else {
678 size_t dst_len = strlen(dst);
Josh Gaoa5cea712015-11-07 15:27:26 -0800679
680 // A path that ends with a slash doesn't have to be a directory if
681 // it doesn't exist yet.
682 if (dst[dst_len - 1] == '/' && dst_exists) {
Josh Gao5d093b22015-10-30 16:57:19 -0700683 sc.Error("failed to access '%s': Not a directory", dst);
684 return false;
685 }
686 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700687 }
Josh Gao5d093b22015-10-30 16:57:19 -0700688
689 for (const char* src_path : srcs) {
690 const char* dst_path = dst;
691 struct stat st;
Josh Gaoa5cea712015-11-07 15:27:26 -0800692 if (stat(src_path, &st) == -1) {
Josh Gao5d093b22015-10-30 16:57:19 -0700693 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
694 success = false;
695 continue;
696 }
697
698 if (S_ISDIR(st.st_mode)) {
Josh Gao8acf06c2015-11-07 15:38:19 -0800699 std::string dst_dir = dst;
700
701 // If the destination path existed originally, the source directory
702 // should be copied as a child of the destination.
703 if (dst_exists) {
704 if (!dst_isdir) {
705 sc.Error("target '%s' is not a directory", dst);
706 return false;
707 }
708 // dst is a POSIX path, so we don't want to use the sysdeps
709 // helpers here.
710 if (dst_dir.back() != '/') {
711 dst_dir.push_back('/');
712 }
713 dst_dir.append(adb_basename(src_path));
714 }
715
716 success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(),
717 false, false);
Josh Gao5d093b22015-10-30 16:57:19 -0700718 continue;
719 }
720
721 std::string path_holder;
Josh Gao8acf06c2015-11-07 15:38:19 -0800722 if (dst_isdir) {
Josh Gao5d093b22015-10-30 16:57:19 -0700723 // If we're copying a local file to a remote directory,
724 // we really want to copy to remote_dir + "/" + local_filename.
725 path_holder = android::base::StringPrintf(
726 "%s/%s", dst_path, adb_basename(src_path).c_str());
727 dst_path = path_holder.c_str();
728 }
729 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
730 }
731
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700732 sc.Print("\n");
Josh Gao5d093b22015-10-30 16:57:19 -0700733 return success;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800734}
735
Josh Gaod9a2fd62015-12-09 14:03:30 -0800736static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) {
737 unsigned mode;
738 std::string dir_path = rpath;
739 dir_path.push_back('/');
740 if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) {
741 sc.Error("failed to stat remote symlink '%s'", dir_path.c_str());
742 return false;
743 }
744 return S_ISDIR(mode);
745}
746
Josh Gao204d21e2015-11-02 16:45:47 -0800747static bool remote_build_list(SyncConnection& sc,
748 std::vector<copyinfo>* filelist,
Josh Gaod20cf382015-11-03 15:23:03 -0800749 const std::string& rpath,
750 const std::string& lpath) {
Josh Gao204d21e2015-11-02 16:45:47 -0800751 std::vector<copyinfo> dirlist;
Josh Gaod9a2fd62015-12-09 14:03:30 -0800752 std::vector<copyinfo> linklist;
Josh Gaoa90563e2015-11-04 14:57:04 -0800753 bool empty_dir = true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800754
Elliott Hughesb628cb12015-08-03 10:38:08 -0700755 // Put the files/dirs in rpath on the lists.
Josh Gaob3cab932015-11-30 10:21:25 -0800756 auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800757 if (IsDotOrDotDot(name)) {
758 return;
759 }
Josh Gao204d21e2015-11-02 16:45:47 -0800760
Josh Gaoa90563e2015-11-04 14:57:04 -0800761 // We found a child that isn't '.' or '..'.
762 empty_dir = false;
763
Josh Gaod9a2fd62015-12-09 14:03:30 -0800764 copyinfo ci(lpath, rpath, name, mode);
Josh Gaoa90563e2015-11-04 14:57:04 -0800765 if (S_ISDIR(mode)) {
766 dirlist.push_back(ci);
Josh Gaod9a2fd62015-12-09 14:03:30 -0800767 } else if (S_ISLNK(mode)) {
768 linklist.push_back(ci);
Josh Gao204d21e2015-11-02 16:45:47 -0800769 } else {
Josh Gaod9a2fd62015-12-09 14:03:30 -0800770 ci.time = time;
771 ci.size = size;
Josh Gaob3cab932015-11-30 10:21:25 -0800772 filelist->push_back(ci);
Josh Gao204d21e2015-11-02 16:45:47 -0800773 }
774 };
775
Josh Gaod20cf382015-11-03 15:23:03 -0800776 if (!sync_ls(sc, rpath.c_str(), callback)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700777 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800778 }
779
Josh Gaod9a2fd62015-12-09 14:03:30 -0800780 // Add the current directory to the list if it was empty, to ensure that it gets created.
Josh Gaoa90563e2015-11-04 14:57:04 -0800781 if (empty_dir) {
Josh Gaod9a2fd62015-12-09 14:03:30 -0800782 copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(rpath), S_IFDIR);
783 filelist->push_back(ci);
Josh Gaoa90563e2015-11-04 14:57:04 -0800784 return true;
785 }
786
Josh Gaod9a2fd62015-12-09 14:03:30 -0800787 // Check each symlink we found to see whether it's a file or directory.
788 for (copyinfo& link_ci : linklist) {
789 if (remote_symlink_isdir(sc, link_ci.rpath)) {
790 dirlist.emplace_back(std::move(link_ci));
791 } else {
792 filelist->emplace_back(std::move(link_ci));
793 }
794 }
795
Elliott Hughesb628cb12015-08-03 10:38:08 -0700796 // Recurse into each directory we found.
Josh Gao204d21e2015-11-02 16:45:47 -0800797 while (!dirlist.empty()) {
798 copyinfo current = dirlist.back();
799 dirlist.pop_back();
Josh Gaoa3b6a062015-11-09 11:12:14 -0800800 if (!remote_build_list(sc, filelist, current.rpath, current.lpath)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700801 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800802 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800803 }
804
Elliott Hughesb628cb12015-08-03 10:38:08 -0700805 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800806}
807
Josh Gaoa3b6a062015-11-09 11:12:14 -0800808static int set_time_and_mode(const std::string& lpath, time_t time,
809 unsigned int mode) {
Greg Hackmann8b689142014-05-06 08:48:18 -0700810 struct utimbuf times = { time, time };
Josh Gaoa3b6a062015-11-09 11:12:14 -0800811 int r1 = utime(lpath.c_str(), &times);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700812
813 /* use umask for permissions */
Josh Gao204d21e2015-11-02 16:45:47 -0800814 mode_t mask = umask(0000);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700815 umask(mask);
Josh Gaoa3b6a062015-11-09 11:12:14 -0800816 int r2 = chmod(lpath.c_str(), mode & ~mask);
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700817
Spencer Low28bc2cb2015-11-07 18:51:54 -0800818 return r1 ? r1 : r2;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700819}
820
Josh Gaod20cf382015-11-03 15:23:03 -0800821static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
822 std::string lpath, bool copy_attrs) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700823 // Make sure that both directory paths end in a slash.
Josh Gaoa5cea712015-11-07 15:27:26 -0800824 // Both paths are known to be nonempty, so we don't need to check.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800825 ensure_trailing_separator(lpath, rpath);
Riley Andrewsc736a942014-12-12 13:12:36 -0800826
Elliott Hughesb628cb12015-08-03 10:38:08 -0700827 // Recursively build the list of files to copy.
Elliott Hughesf5cdc1d2015-10-27 16:03:15 -0700828 sc.Print("pull: building file list...");
Josh Gao204d21e2015-11-02 16:45:47 -0800829 std::vector<copyinfo> filelist;
Josh Gaod20cf382015-11-03 15:23:03 -0800830 if (!remote_build_list(sc, &filelist, rpath.c_str(), lpath.c_str())) {
Josh Gao204d21e2015-11-02 16:45:47 -0800831 return false;
832 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700833
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800834 int pulled = 0;
835 int skipped = 0;
Josh Gao204d21e2015-11-02 16:45:47 -0800836 for (const copyinfo &ci : filelist) {
Josh Gaocb094c62015-11-03 14:44:04 -0800837 if (!ci.skip) {
Josh Gaoa3b6a062015-11-09 11:12:14 -0800838 sc.Printf("pull: %s -> %s", ci.rpath.c_str(), ci.lpath.c_str());
Josh Gaoa90563e2015-11-04 14:57:04 -0800839
840 if (S_ISDIR(ci.mode)) {
841 // Entry is for an empty directory, create it and continue.
842 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800843 if (!mkdirs(ci.lpath)) {
Josh Gaoa90563e2015-11-04 14:57:04 -0800844 sc.Error("failed to create directory '%s': %s",
Josh Gaoa3b6a062015-11-09 11:12:14 -0800845 ci.lpath.c_str(), strerror(errno));
Josh Gaoa90563e2015-11-04 14:57:04 -0800846 return false;
847 }
848 pulled++;
849 continue;
850 }
851
Josh Gaoa3b6a062015-11-09 11:12:14 -0800852 if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700853 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800854 }
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700855
Josh Gaoa3b6a062015-11-09 11:12:14 -0800856 if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700857 return false;
Lajos Molnar4e23e3c2013-04-19 12:41:09 -0700858 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800859 pulled++;
860 } else {
861 skipped++;
862 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800863 }
864
Josh Gaod20cf382015-11-03 15:23:03 -0800865 sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath.c_str(),
866 pulled, (pulled == 1) ? "" : "s", skipped,
867 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesb628cb12015-08-03 10:38:08 -0700868 return true;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800869}
870
Josh Gao5d093b22015-10-30 16:57:19 -0700871bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
872 bool copy_attrs) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700873 SyncConnection sc;
874 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800875
Josh Gao5d093b22015-10-30 16:57:19 -0700876 bool success = true;
Josh Gao5d093b22015-10-30 16:57:19 -0700877 struct stat st;
Josh Gaoa5cea712015-11-07 15:27:26 -0800878 bool dst_exists = true;
879
880 if (stat(dst, &st) == -1) {
881 dst_exists = false;
882
883 // If we're only pulling one path, the destination path might point to
Josh Gao5d093b22015-10-30 16:57:19 -0700884 // a path that doesn't exist yet.
Josh Gaoa5cea712015-11-07 15:27:26 -0800885 if (srcs.size() == 1 && errno == ENOENT) {
886 // However, its parent must exist.
887 struct stat parent_st;
888 if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
889 sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
890 return false;
891 }
892 } else {
893 sc.Error("failed to access '%s': %s", dst, strerror(errno));
Josh Gao5d093b22015-10-30 16:57:19 -0700894 return false;
895 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800896 }
897
Josh Gao8acf06c2015-11-07 15:38:19 -0800898 bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
899 if (!dst_isdir) {
Josh Gao5d093b22015-10-30 16:57:19 -0700900 if (srcs.size() > 1) {
901 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700902 return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800903 } else {
Josh Gao5d093b22015-10-30 16:57:19 -0700904 size_t dst_len = strlen(dst);
Josh Gaoa5cea712015-11-07 15:27:26 -0800905
906 // A path that ends with a slash doesn't have to be a directory if
907 // it doesn't exist yet.
Josh Gaoa3b6a062015-11-09 11:12:14 -0800908 if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
Josh Gao5d093b22015-10-30 16:57:19 -0700909 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesb628cb12015-08-03 10:38:08 -0700910 return false;
Elliott Hughesd189cfb2015-07-30 17:42:01 -0700911 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800912 }
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800913 }
Elliott Hughesb628cb12015-08-03 10:38:08 -0700914
Josh Gao5d093b22015-10-30 16:57:19 -0700915 for (const char* src_path : srcs) {
916 const char* dst_path = dst;
Josh Gaoa5cea712015-11-07 15:27:26 -0800917 unsigned src_mode, src_time;
918 if (!sync_stat(sc, src_path, &src_time, &src_mode, nullptr)) {
Josh Gaod9a2fd62015-12-09 14:03:30 -0800919 sc.Error("failed to stat remote object '%s'", src_path);
Josh Gaoa5cea712015-11-07 15:27:26 -0800920 return false;
921 }
922 if (src_mode == 0) {
Josh Gao5d093b22015-10-30 16:57:19 -0700923 sc.Error("remote object '%s' does not exist", src_path);
924 success = false;
925 continue;
926 }
927
Josh Gaod9a2fd62015-12-09 14:03:30 -0800928 bool src_isdir = S_ISDIR(src_mode);
929 if (S_ISLNK(src_mode)) {
930 src_isdir = remote_symlink_isdir(sc, src_path);
931 }
932
933 if ((src_mode & (S_IFREG | S_IFDIR | S_IFBLK | S_IFCHR)) == 0) {
934 sc.Error("skipping remote object '%s' (mode = 0o%o)", src_path, src_mode);
935 continue;
936 }
937
938 if (src_isdir) {
Josh Gao8acf06c2015-11-07 15:38:19 -0800939 std::string dst_dir = dst;
940
941 // If the destination path existed originally, the source directory
942 // should be copied as a child of the destination.
943 if (dst_exists) {
944 if (!dst_isdir) {
945 sc.Error("target '%s' is not a directory", dst);
946 return false;
947 }
948 if (!adb_is_separator(dst_dir.back())) {
949 dst_dir.push_back(OS_PATH_SEPARATOR);
950 }
951 dst_dir.append(adb_basename(src_path));
952 }
953
Josh Gaod9a2fd62015-12-09 14:03:30 -0800954 success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
Josh Gao5d093b22015-10-30 16:57:19 -0700955 continue;
956 } else {
Josh Gaod9a2fd62015-12-09 14:03:30 -0800957 std::string path_holder;
958 if (dst_isdir) {
959 // If we're copying a remote file to a local directory, we
960 // really want to copy to local_dir + OS_PATH_SEPARATOR +
961 // basename(remote).
962 path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
963 adb_basename(src_path).c_str());
964 dst_path = path_holder.c_str();
965 }
966
967 if (!sync_recv(sc, src_path, dst_path)) {
968 success = false;
969 continue;
970 }
971
972 if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) {
973 success = false;
974 continue;
975 }
Josh Gao5d093b22015-10-30 16:57:19 -0700976 }
977 }
978
979 sc.Print("\n");
980 return success;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800981}
982
Elliott Hughesb628cb12015-08-03 10:38:08 -0700983bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesb628cb12015-08-03 10:38:08 -0700984 SyncConnection sc;
985 if (!sc.IsValid()) return false;
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800986
Josh Gaod20cf382015-11-03 15:23:03 -0800987 return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
The Android Open Source Project9ca14dc2009-03-03 19:32:55 -0800988}