blob: 320891de163f3202b7712d1c46f027ed1e8ecc0f [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 Hughesae5a6c02015-09-27 12:55:37 -070044#include <base/file.h>
Elliott Hughesaa245492015-08-03 10:38:08 -070045#include <base/strings.h>
Elliott Hughes5c742702015-07-30 17:42:01 -070046#include <base/stringprintf.h>
47
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 Hughesaa245492015-08-03 10:38:08 -070054class SyncConnection {
55 public:
Elliott Hughesb708d162015-10-27 16:03:15 -070056 SyncConnection() : total_bytes(0), start_time_ms_(CurrentTimeMs()) {
Elliott Hughesaa245492015-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 Hughesb708d162015-10-27 16:03:15 -070062 Error("connect failed: %s", error.c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -070063 }
64 }
65
66 ~SyncConnection() {
67 if (!IsValid()) return;
68
Spencer Low351ecd12015-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 Hughesaa245492015-08-03 10:38:08 -070078 adb_close(fd);
79 }
80
81 bool IsValid() { return fd >= 0; }
82
Elliott Hughesae5a6c02015-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 Hughesb708d162015-10-27 16:03:15 -070086 Error("SendRequest failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-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 Hughes6d929972015-10-27 13:40:35 -070093 std::vector<char> buf(sizeof(SyncRequest) + path_length);
94 SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
Elliott Hughesae5a6c02015-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 Hughes6d929972015-10-27 13:40:35 -0700100 return WriteFdExactly(fd, &buf[0], buf.size());
Elliott Hughesae5a6c02015-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 Hughesb708d162015-10-27 16:03:15 -0700106 const char* rpath,
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800107 unsigned mtime,
108 const char* data, size_t data_length) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700109 Print(rpath);
110
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700111 size_t path_length = strlen(path_and_mode);
112 if (path_length > 1024) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700113 Error("SendSmallFile failed: path too long: %zu", path_length);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700114 errno = ENAMETOOLONG;
115 return false;
116 }
117
Elliott Hughes6d929972015-10-27 13:40:35 -0700118 std::vector<char> buf(sizeof(SyncRequest) + path_length +
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800119 sizeof(SyncRequest) + data_length +
120 sizeof(SyncRequest));
Elliott Hughes6d929972015-10-27 13:40:35 -0700121 char* p = &buf[0];
Elliott Hughesae5a6c02015-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 Hughes6d929972015-10-27 13:40:35 -0700142 if (!WriteFdExactly(fd, &buf[0], (p - &buf[0]))) return false;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700143
144 total_bytes += data_length;
145 return true;
146 }
147
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800148 bool SendLargeFile(const char* path_and_mode,
149 const char* lpath, const char* rpath,
150 unsigned mtime) {
151 if (!SendRequest(ID_SEND, path_and_mode)) {
152 Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
153 return false;
154 }
155
156 struct stat st;
157 if (stat(lpath, &st) == -1) {
158 Error("cannot stat '%s': %s", lpath, strerror(errno));
159 return false;
160 }
161
162 uint64_t total_size = st.st_size;
163 uint64_t bytes_copied = 0;
164
165 int lfd = adb_open(lpath, O_RDONLY);
166 if (lfd < 0) {
167 Error("cannot open '%s': %s", lpath, strerror(errno));
168 return false;
169 }
170
171 syncsendbuf sbuf;
172 sbuf.id = ID_DATA;
173 while (true) {
174 int ret = adb_read(lfd, sbuf.data, max);
175 if (ret <= 0) {
176 if (ret < 0) {
177 Error("cannot read '%s': %s", lpath, strerror(errno));
178 adb_close(lfd);
179 return false;
180 }
181 break;
182 }
183
184 sbuf.size = ret;
185 if (!WriteFdExactly(fd, &sbuf, sizeof(unsigned) * 2 + ret)) {
186 adb_close(lfd);
187 return false;
188 }
189 total_bytes += ret;
190
191 bytes_copied += ret;
192
193 int percentage = static_cast<int>(bytes_copied * 100 / total_size);
194 Printf("%s: %d%%", rpath, percentage);
195 }
196
197 adb_close(lfd);
198
199 syncmsg msg;
200 msg.data.id = ID_DONE;
201 msg.data.size = mtime;
202 if (!WriteFdExactly(fd, &msg.data, sizeof(msg.data))) {
203 Error("failed to send ID_DONE message for '%s': %s", rpath, strerror(errno));
204 return false;
205 }
206
207 return true;
208 }
209
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700210 bool CopyDone(const char* from, const char* to) {
211 syncmsg msg;
212 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700213 Error("failed to copy '%s' to '%s': no ID_DONE: %s", from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700214 return false;
215 }
216 if (msg.status.id == ID_OKAY) {
217 return true;
218 }
219 if (msg.status.id != ID_FAIL) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700220 Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700221 return false;
222 }
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700223 return ReportCopyFailure(from, to, msg);
224 }
225
226 bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
Elliott Hughes6d929972015-10-27 13:40:35 -0700227 std::vector<char> buf(msg.status.msglen + 1);
228 if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700229 Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
230 from, to, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700231 return false;
232 }
Elliott Hughes6d929972015-10-27 13:40:35 -0700233 buf[msg.status.msglen] = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700234 Error("failed to copy '%s' to '%s': %s", from, to, &buf[0]);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700235 return false;
236 }
237
Elliott Hughesb708d162015-10-27 16:03:15 -0700238 std::string TransferRate() {
239 uint64_t ms = CurrentTimeMs() - start_time_ms_;
240 if (total_bytes == 0 || ms == 0) return "";
241
242 double s = static_cast<double>(ms) / 1000LL;
243 double rate = (static_cast<double>(total_bytes) / s) / (1024*1024);
244 return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
245 rate, total_bytes, s);
246 }
247
248 void Print(const std::string& s) {
249 // TODO: we actually don't want ELIDE; we want "ELIDE if smart, FULL if dumb".
250 line_printer_.Print(s, LinePrinter::ELIDE);
251 }
252
Josh Gao983c41c2015-11-02 17:15:57 -0800253 void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
254 std::string s;
255 va_list ap;
256 va_start(ap, fmt);
257 android::base::StringAppendV(&s, fmt, ap);
258 va_end(ap);
259
260 Print(s);
261 }
262
Elliott Hughesb708d162015-10-27 16:03:15 -0700263 void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
264 std::string s = "adb: error: ";
265
266 va_list ap;
267 va_start(ap, fmt);
268 android::base::StringAppendV(&s, fmt, ap);
269 va_end(ap);
270
271 line_printer_.Print(s, LinePrinter::FULL);
272 }
273
Josh Gao21abf5a2015-11-07 17:18:44 -0800274 void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
275 std::string s = "adb: warning: ";
276
277 va_list ap;
278 va_start(ap, fmt);
279 android::base::StringAppendV(&s, fmt, ap);
280 va_end(ap);
281
282 line_printer_.Print(s, LinePrinter::FULL);
283 }
284
Elliott Hughesaa245492015-08-03 10:38:08 -0700285 uint64_t total_bytes;
286
287 // TODO: add a char[max] buffer here, to replace syncsendbuf...
288 int fd;
289 size_t max;
290
291 private:
Elliott Hughesb708d162015-10-27 16:03:15 -0700292 uint64_t start_time_ms_;
293
294 LinePrinter line_printer_;
Elliott Hughesaa245492015-08-03 10:38:08 -0700295
Spencer Low351ecd12015-10-14 17:32:44 -0700296 bool SendQuit() {
297 return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
Elliott Hughesaa245492015-08-03 10:38:08 -0700298 }
299
Elliott Hughesb708d162015-10-27 16:03:15 -0700300 static uint64_t CurrentTimeMs() {
301 struct timeval tv;
302 gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
303 return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
Elliott Hughesaa245492015-08-03 10:38:08 -0700304 }
305};
306
Josh Gaocda6a2b2015-11-02 16:45:47 -0800307typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
Elliott Hughesaa245492015-08-03 10:38:08 -0700308
Josh Gaocda6a2b2015-11-02 16:45:47 -0800309static bool sync_ls(SyncConnection& sc, const char* path,
310 std::function<sync_ls_cb> func) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700311 if (!sc.SendRequest(ID_LIST, path)) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700312
313 while (true) {
314 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700315 if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
Elliott Hughesaa245492015-08-03 10:38:08 -0700316
317 if (msg.dent.id == ID_DONE) return true;
318 if (msg.dent.id != ID_DENT) return false;
319
Elliott Hughesf4465202015-08-24 14:27:03 -0700320 size_t len = msg.dent.namelen;
Elliott Hughesaa245492015-08-03 10:38:08 -0700321 if (len > 256) return false; // TODO: resize buffer? continue?
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800322
Elliott Hughes5c742702015-07-30 17:42:01 -0700323 char buf[257];
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700324 if (!ReadFdExactly(sc.fd, buf, len)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800325 buf[len] = 0;
326
Josh Gaocda6a2b2015-11-02 16:45:47 -0800327 func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800328 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800329}
330
Elliott Hughesaa245492015-08-03 10:38:08 -0700331static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
332 unsigned int* mode, unsigned int* size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800333 syncmsg msg;
Elliott Hughesaa245492015-08-03 10:38:08 -0700334 if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
335 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800336 }
337
Elliott Hughesf4465202015-08-24 14:27:03 -0700338 if (timestamp) *timestamp = msg.stat.time;
339 if (mode) *mode = msg.stat.mode;
340 if (size) *size = msg.stat.size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800341
Elliott Hughesaa245492015-08-03 10:38:08 -0700342 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800343}
344
Elliott Hughesaa245492015-08-03 10:38:08 -0700345static bool sync_stat(SyncConnection& sc, const char* path,
346 unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700347 return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800348}
349
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700350static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
Elliott Hughesb708d162015-10-27 16:03:15 -0700351 unsigned mtime, mode_t mode)
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700352{
353 std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
354
355 if (S_ISLNK(mode)) {
356#if !defined(_WIN32)
357 char buf[PATH_MAX];
358 ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
359 if (data_length == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700360 sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700361 return false;
362 }
363 buf[data_length++] = '\0';
364
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800365 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, mtime, buf, data_length)) return false;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700366 return sc.CopyDone(lpath, rpath);
367#endif
368 }
369
370 if (!S_ISREG(mode)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700371 sc.Error("local file '%s' has unsupported mode: 0o%o", lpath, mode);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700372 return false;
373 }
374
375 struct stat st;
376 if (stat(lpath, &st) == -1) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700377 sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700378 return false;
379 }
380 if (st.st_size < SYNC_DATA_MAX) {
381 std::string data;
382 if (!android::base::ReadFileToString(lpath, &data)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700383 sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700384 return false;
385 }
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800386 if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, mtime, data.data(), data.size())) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700387 return false;
388 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700389 } else {
Elliott Hughes6aab58c2015-11-20 17:35:17 -0800390 if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700391 return false;
392 }
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700393 }
394 return sc.CopyDone(lpath, rpath);
395}
396
Elliott Hughesb708d162015-10-27 16:03:15 -0700397static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
398 sc.Print(rpath);
399
Elliott Hughesaa245492015-08-03 10:38:08 -0700400 unsigned size = 0;
Elliott Hughesb708d162015-10-27 16:03:15 -0700401 if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
Mark Lindner76f2a932014-03-11 17:55:59 -0700402
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700403 if (!sc.SendRequest(ID_RECV, rpath)) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800404
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700405 adb_unlink(lpath);
Josh Gaof6e65e32015-11-17 14:08:20 -0800406 const std::string dirpath = adb_dirname(lpath);
407 if (!mkdirs(dirpath.c_str())) {
408 sc.Error("failed to create parent directory '%s': %s", dirpath.c_str(), strerror(errno));
Josh Gao45b6fc82015-11-04 14:51:23 -0800409 return false;
410 }
411
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700412 int lfd = adb_creat(lpath, 0644);
413 if (lfd < 0) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700414 sc.Error("cannot create '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700415 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800416 }
417
Elliott Hughesb708d162015-10-27 16:03:15 -0700418 uint64_t bytes_copied = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700419 while (true) {
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700420 syncmsg msg;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700421 if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
Spencer Lowd8cce182015-08-28 01:07:30 -0700422 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700423 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700424 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800425 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800426
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700427 if (msg.data.id == ID_DONE) break;
428
429 if (msg.data.id != ID_DATA) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800430 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700431 adb_unlink(lpath);
432 sc.ReportCopyFailure(rpath, lpath, msg);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700433 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800434 }
435
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700436 if (msg.data.size > sc.max) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700437 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 -0800438 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700439 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700440 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800441 }
442
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700443 char buffer[SYNC_DATA_MAX];
444 if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800445 adb_close(lfd);
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700446 adb_unlink(lpath);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700447 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800448 }
449
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700450 if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700451 sc.Error("cannot write '%s': %s", lpath, strerror(errno));
Elliott Hughes8b43c3e2015-10-23 21:06:11 -0700452 adb_close(lfd);
453 adb_unlink(lpath);
454 return false;
455 }
456
457 sc.total_bytes += msg.data.size;
Mark Lindner76f2a932014-03-11 17:55:59 -0700458
Elliott Hughesb708d162015-10-27 16:03:15 -0700459 bytes_copied += msg.data.size;
460
461 int percentage = static_cast<int>(bytes_copied * 100 / size);
Josh Gao983c41c2015-11-02 17:15:57 -0800462 sc.Printf("%s: %d%%", rpath, percentage);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800463 }
464
465 adb_close(lfd);
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700466 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800467}
468
Elliott Hughesaa245492015-08-03 10:38:08 -0700469bool do_sync_ls(const char* path) {
470 SyncConnection sc;
471 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800472
Josh Gaocda6a2b2015-11-02 16:45:47 -0800473 return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
474 const char* name) {
475 printf("%08x %08x %08x %s\n", mode, size, time, name);
476 });
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800477}
478
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800479struct copyinfo
480{
Josh Gao1a025302015-11-09 11:12:14 -0800481 std::string lpath;
482 std::string rpath;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800483 unsigned int time;
484 unsigned int mode;
Elliott Hughesae5a6c02015-09-27 12:55:37 -0700485 uint64_t size;
Josh Gaofc7c3b62015-11-03 14:44:04 -0800486 bool skip;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800487};
488
Josh Gao1a025302015-11-09 11:12:14 -0800489static void ensure_trailing_separator(std::string& lpath, std::string& rpath) {
490 if (!adb_is_separator(lpath.back())) {
491 lpath.push_back(OS_PATH_SEPARATOR);
492 }
493 if (rpath.back() != '/') {
494 rpath.push_back('/');
495 }
496}
497
498static copyinfo mkcopyinfo(std::string lpath, std::string rpath,
Josh Gao65800962015-11-04 14:57:04 -0800499 const std::string& name, unsigned int mode) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800500 copyinfo result;
Josh Gao1a025302015-11-09 11:12:14 -0800501 result.lpath = std::move(lpath);
502 result.rpath = std::move(rpath);
503 ensure_trailing_separator(result.lpath, result.rpath);
504 result.lpath.append(name);
505 result.rpath.append(name);
Josh Gao12a2ae92015-11-07 15:27:26 -0800506
Josh Gao1a025302015-11-09 11:12:14 -0800507 if (S_ISDIR(mode)) {
508 ensure_trailing_separator(result.lpath, result.rpath);
Josh Gaod9731572015-11-03 15:23:03 -0800509 }
Josh Gao65800962015-11-04 14:57:04 -0800510
Josh Gaocda6a2b2015-11-02 16:45:47 -0800511 result.time = 0;
Josh Gao65800962015-11-04 14:57:04 -0800512 result.mode = mode;
Josh Gaocda6a2b2015-11-02 16:45:47 -0800513 result.size = 0;
Josh Gaofc7c3b62015-11-03 14:44:04 -0800514 result.skip = false;
Josh Gaocda6a2b2015-11-02 16:45:47 -0800515 return result;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800516}
517
Elliott Hughesaa245492015-08-03 10:38:08 -0700518static bool IsDotOrDotDot(const char* name) {
519 return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
520}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800521
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800522static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* filelist,
523 const std::string& lpath,
524 const std::string& rpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800525 std::vector<copyinfo> dirlist;
Josh Gaod9731572015-11-03 15:23:03 -0800526 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
Elliott Hughesaa245492015-08-03 10:38:08 -0700527 if (!dir) {
Josh Gaod9731572015-11-03 15:23:03 -0800528 sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800529 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800530 }
531
Josh Gao65800962015-11-04 14:57:04 -0800532 bool empty_dir = true;
Elliott Hughesb708d162015-10-27 16:03:15 -0700533 dirent* de;
Elliott Hughesaa245492015-08-03 10:38:08 -0700534 while ((de = readdir(dir.get()))) {
Josh Gao65800962015-11-04 14:57:04 -0800535 if (IsDotOrDotDot(de->d_name)) {
536 continue;
537 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700538
Josh Gao65800962015-11-04 14:57:04 -0800539 empty_dir = false;
Josh Gaod9731572015-11-03 15:23:03 -0800540 std::string stat_path = lpath + de->d_name;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800541
Elliott Hughesaa245492015-08-03 10:38:08 -0700542 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800543 if (lstat(stat_path.c_str(), &st) == -1) {
Josh Gaod9731572015-11-03 15:23:03 -0800544 sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
545 strerror(errno));
Josh Gao12a2ae92015-11-07 15:27:26 -0800546 continue;
547 }
548
549 copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, st.st_mode);
550 if (S_ISDIR(st.st_mode)) {
551 dirlist.push_back(ci);
552 } else {
553 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
554 sc.Error("skipping special file '%s'", lpath.c_str());
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800555 ci.skip = true;
Josh Gao12a2ae92015-11-07 15:27:26 -0800556 } else {
557 ci.time = st.st_mtime;
558 ci.size = st.st_size;
Josh Gao12a2ae92015-11-07 15:27:26 -0800559 }
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800560 filelist->push_back(ci);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800561 }
562 }
563
Elliott Hughesaa245492015-08-03 10:38:08 -0700564 // Close this directory and recurse.
565 dir.reset();
Josh Gao65800962015-11-04 14:57:04 -0800566
567 // Add the current directory to the list if it was empty, to ensure that
568 // it gets created.
569 if (empty_dir) {
570 // TODO(b/25566053): Make pushing empty directories work.
571 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao21abf5a2015-11-07 17:18:44 -0800572 sc.Warning("skipping empty directory '%s'", lpath.c_str());
Josh Gao65800962015-11-04 14:57:04 -0800573 copyinfo ci = mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
574 adb_basename(lpath), S_IFDIR);
575 ci.skip = true;
576 filelist->push_back(ci);
577 return true;
578 }
579
Josh Gaocda6a2b2015-11-02 16:45:47 -0800580 for (const copyinfo& ci : dirlist) {
Josh Gao1a025302015-11-09 11:12:14 -0800581 local_build_list(sc, filelist, ci.lpath, ci.rpath);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800582 }
583
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800584 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800585}
586
Josh Gaod9731572015-11-03 15:23:03 -0800587static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
588 std::string rpath, bool check_timestamps,
589 bool list_only) {
590 // Make sure that both directory paths end in a slash.
Josh Gao1a025302015-11-09 11:12:14 -0800591 // Both paths are known to be nonempty, so we don't need to check.
592 ensure_trailing_separator(lpath, rpath);
Josh Gaod9731572015-11-03 15:23:03 -0800593
594 // Recursively build the list of files to copy.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800595 std::vector<copyinfo> filelist;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800596 int pushed = 0;
597 int skipped = 0;
Josh Gaocd7c1ed2015-11-03 15:26:38 -0800598 if (!local_build_list(sc, &filelist, lpath, rpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700599 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800600 }
601
Elliott Hughesaa245492015-08-03 10:38:08 -0700602 if (check_timestamps) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800603 for (const copyinfo& ci : filelist) {
Josh Gao1a025302015-11-09 11:12:14 -0800604 if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
Josh Gaod9731572015-11-03 15:23:03 -0800605 return false;
606 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800607 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800608 for (copyinfo& ci : filelist) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800609 unsigned int timestamp, mode, size;
Josh Gaod9731572015-11-03 15:23:03 -0800610 if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
611 return false;
612 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800613 if (size == ci.size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800614 /* for links, we cannot update the atime/mtime */
Josh Gaocda6a2b2015-11-02 16:45:47 -0800615 if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
616 (S_ISLNK(ci.mode & mode) && timestamp >= ci.time)) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800617 ci.skip = true;
Elliott Hughesaa245492015-08-03 10:38:08 -0700618 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800619 }
620 }
621 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800622
623 for (const copyinfo& ci : filelist) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800624 if (!ci.skip) {
Elliott Hughesb708d162015-10-27 16:03:15 -0700625 if (list_only) {
Josh Gao1a025302015-11-09 11:12:14 -0800626 sc.Error("would push: %s -> %s", ci.lpath.c_str(),
627 ci.rpath.c_str());
Elliott Hughesb708d162015-10-27 16:03:15 -0700628 } else {
Josh Gao1a025302015-11-09 11:12:14 -0800629 if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time,
Josh Gaod9731572015-11-03 15:23:03 -0800630 ci.mode)) {
631 return false;
Elliott Hughesb708d162015-10-27 16:03:15 -0700632 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800633 }
634 pushed++;
635 } else {
636 skipped++;
637 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800638 }
639
Josh Gaod9731572015-11-03 15:23:03 -0800640 sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath.c_str(),
641 pushed, (pushed == 1) ? "" : "s", skipped,
642 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700643 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800644}
645
Josh Gao05786772015-10-30 16:57:19 -0700646bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700647 SyncConnection sc;
648 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800649
Josh Gao05786772015-10-30 16:57:19 -0700650 bool success = true;
Josh Gao12a2ae92015-11-07 15:27:26 -0800651 unsigned dst_mode;
652 if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false;
653 bool dst_exists = (dst_mode != 0);
Josh Gao07db1192015-11-07 15:38:19 -0800654 bool dst_isdir = S_ISDIR(dst_mode);
Josh Gao05786772015-10-30 16:57:19 -0700655
Josh Gao07db1192015-11-07 15:38:19 -0800656 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700657 if (srcs.size() > 1) {
658 sc.Error("target '%s' is not a directory", dst);
659 return false;
660 } else {
661 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -0800662
663 // A path that ends with a slash doesn't have to be a directory if
664 // it doesn't exist yet.
665 if (dst[dst_len - 1] == '/' && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -0700666 sc.Error("failed to access '%s': Not a directory", dst);
667 return false;
668 }
669 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700670 }
Josh Gao05786772015-10-30 16:57:19 -0700671
672 for (const char* src_path : srcs) {
673 const char* dst_path = dst;
674 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800675 if (stat(src_path, &st) == -1) {
Josh Gao05786772015-10-30 16:57:19 -0700676 sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
677 success = false;
678 continue;
679 }
680
681 if (S_ISDIR(st.st_mode)) {
Josh Gao07db1192015-11-07 15:38:19 -0800682 std::string dst_dir = dst;
683
684 // If the destination path existed originally, the source directory
685 // should be copied as a child of the destination.
686 if (dst_exists) {
687 if (!dst_isdir) {
688 sc.Error("target '%s' is not a directory", dst);
689 return false;
690 }
691 // dst is a POSIX path, so we don't want to use the sysdeps
692 // helpers here.
693 if (dst_dir.back() != '/') {
694 dst_dir.push_back('/');
695 }
696 dst_dir.append(adb_basename(src_path));
697 }
698
699 success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(),
700 false, false);
Josh Gao05786772015-10-30 16:57:19 -0700701 continue;
702 }
703
704 std::string path_holder;
Josh Gao07db1192015-11-07 15:38:19 -0800705 if (dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700706 // If we're copying a local file to a remote directory,
707 // we really want to copy to remote_dir + "/" + local_filename.
708 path_holder = android::base::StringPrintf(
709 "%s/%s", dst_path, adb_basename(src_path).c_str());
710 dst_path = path_holder.c_str();
711 }
712 success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
713 }
714
Elliott Hughesb708d162015-10-27 16:03:15 -0700715 sc.Print("\n");
Josh Gao05786772015-10-30 16:57:19 -0700716 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800717}
718
Josh Gaocda6a2b2015-11-02 16:45:47 -0800719static bool remote_build_list(SyncConnection& sc,
720 std::vector<copyinfo>* filelist,
Josh Gaod9731572015-11-03 15:23:03 -0800721 const std::string& rpath,
722 const std::string& lpath) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800723 std::vector<copyinfo> dirlist;
Josh Gao65800962015-11-04 14:57:04 -0800724 bool empty_dir = true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800725
Elliott Hughesaa245492015-08-03 10:38:08 -0700726 // Put the files/dirs in rpath on the lists.
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800727 auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
Josh Gao65800962015-11-04 14:57:04 -0800728 if (IsDotOrDotDot(name)) {
729 return;
730 }
Josh Gaocda6a2b2015-11-02 16:45:47 -0800731
Josh Gao65800962015-11-04 14:57:04 -0800732 // We found a child that isn't '.' or '..'.
733 empty_dir = false;
734
Josh Gao1a025302015-11-09 11:12:14 -0800735 copyinfo ci = mkcopyinfo(lpath, rpath, name, mode);
Josh Gao65800962015-11-04 14:57:04 -0800736 if (S_ISDIR(mode)) {
737 dirlist.push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -0800738 } else {
Josh Gaodd6cc4d2015-11-30 10:21:25 -0800739 if (S_ISREG(mode) || S_ISLNK(mode)) {
740 ci.time = time;
741 ci.size = size;
742 } else {
743 sc.Warning("skipping special file '%s'\n", name);
744 ci.skip = true;
745 }
746 filelist->push_back(ci);
Josh Gaocda6a2b2015-11-02 16:45:47 -0800747 }
748 };
749
Josh Gaod9731572015-11-03 15:23:03 -0800750 if (!sync_ls(sc, rpath.c_str(), callback)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700751 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800752 }
753
Josh Gao65800962015-11-04 14:57:04 -0800754 // Add the current directory to the list if it was empty, to ensure that
755 // it gets created.
756 if (empty_dir) {
Josh Gao1a025302015-11-09 11:12:14 -0800757 filelist->push_back(mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
Josh Gao65800962015-11-04 14:57:04 -0800758 adb_basename(rpath), S_IFDIR));
759 return true;
760 }
761
Elliott Hughesaa245492015-08-03 10:38:08 -0700762 // Recurse into each directory we found.
Josh Gaocda6a2b2015-11-02 16:45:47 -0800763 while (!dirlist.empty()) {
764 copyinfo current = dirlist.back();
765 dirlist.pop_back();
Josh Gao1a025302015-11-09 11:12:14 -0800766 if (!remote_build_list(sc, filelist, current.rpath, current.lpath)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700767 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800768 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800769 }
770
Elliott Hughesaa245492015-08-03 10:38:08 -0700771 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800772}
773
Josh Gao1a025302015-11-09 11:12:14 -0800774static int set_time_and_mode(const std::string& lpath, time_t time,
775 unsigned int mode) {
Greg Hackmann7a5e2bd2014-05-06 08:48:18 -0700776 struct utimbuf times = { time, time };
Josh Gao1a025302015-11-09 11:12:14 -0800777 int r1 = utime(lpath.c_str(), &times);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700778
779 /* use umask for permissions */
Josh Gaocda6a2b2015-11-02 16:45:47 -0800780 mode_t mask = umask(0000);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700781 umask(mask);
Josh Gao1a025302015-11-09 11:12:14 -0800782 int r2 = chmod(lpath.c_str(), mode & ~mask);
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700783
Spencer Low363af562015-11-07 18:51:54 -0800784 return r1 ? r1 : r2;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700785}
786
Josh Gaod9731572015-11-03 15:23:03 -0800787static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
788 std::string lpath, bool copy_attrs) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700789 // Make sure that both directory paths end in a slash.
Josh Gao12a2ae92015-11-07 15:27:26 -0800790 // Both paths are known to be nonempty, so we don't need to check.
Josh Gao1a025302015-11-09 11:12:14 -0800791 ensure_trailing_separator(lpath, rpath);
Riley Andrews4d04d242014-12-12 13:12:36 -0800792
Elliott Hughesaa245492015-08-03 10:38:08 -0700793 // Recursively build the list of files to copy.
Elliott Hughesb708d162015-10-27 16:03:15 -0700794 sc.Print("pull: building file list...");
Josh Gaocda6a2b2015-11-02 16:45:47 -0800795 std::vector<copyinfo> filelist;
Josh Gaod9731572015-11-03 15:23:03 -0800796 if (!remote_build_list(sc, &filelist, rpath.c_str(), lpath.c_str())) {
Josh Gaocda6a2b2015-11-02 16:45:47 -0800797 return false;
798 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700799
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800800 int pulled = 0;
801 int skipped = 0;
Josh Gaocda6a2b2015-11-02 16:45:47 -0800802 for (const copyinfo &ci : filelist) {
Josh Gaofc7c3b62015-11-03 14:44:04 -0800803 if (!ci.skip) {
Josh Gao1a025302015-11-09 11:12:14 -0800804 sc.Printf("pull: %s -> %s", ci.rpath.c_str(), ci.lpath.c_str());
Josh Gao65800962015-11-04 14:57:04 -0800805
806 if (S_ISDIR(ci.mode)) {
807 // Entry is for an empty directory, create it and continue.
808 // TODO(b/25457350): We don't preserve permissions on directories.
Josh Gao1a025302015-11-09 11:12:14 -0800809 if (!mkdirs(ci.lpath)) {
Josh Gao65800962015-11-04 14:57:04 -0800810 sc.Error("failed to create directory '%s': %s",
Josh Gao1a025302015-11-09 11:12:14 -0800811 ci.lpath.c_str(), strerror(errno));
Josh Gao65800962015-11-04 14:57:04 -0800812 return false;
813 }
814 pulled++;
815 continue;
816 }
817
Josh Gao1a025302015-11-09 11:12:14 -0800818 if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700819 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800820 }
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700821
Josh Gao1a025302015-11-09 11:12:14 -0800822 if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700823 return false;
Lajos Molnarde8ff4a2013-04-19 12:41:09 -0700824 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800825 pulled++;
826 } else {
827 skipped++;
828 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800829 }
830
Josh Gaod9731572015-11-03 15:23:03 -0800831 sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath.c_str(),
832 pulled, (pulled == 1) ? "" : "s", skipped,
833 (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
Elliott Hughesaa245492015-08-03 10:38:08 -0700834 return true;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800835}
836
Josh Gao05786772015-10-30 16:57:19 -0700837bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
838 bool copy_attrs) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700839 SyncConnection sc;
840 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800841
Josh Gao05786772015-10-30 16:57:19 -0700842 bool success = true;
Josh Gao05786772015-10-30 16:57:19 -0700843 struct stat st;
Josh Gao12a2ae92015-11-07 15:27:26 -0800844 bool dst_exists = true;
845
846 if (stat(dst, &st) == -1) {
847 dst_exists = false;
848
849 // If we're only pulling one path, the destination path might point to
Josh Gao05786772015-10-30 16:57:19 -0700850 // a path that doesn't exist yet.
Josh Gao12a2ae92015-11-07 15:27:26 -0800851 if (srcs.size() == 1 && errno == ENOENT) {
852 // However, its parent must exist.
853 struct stat parent_st;
854 if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
855 sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
856 return false;
857 }
858 } else {
859 sc.Error("failed to access '%s': %s", dst, strerror(errno));
Josh Gao05786772015-10-30 16:57:19 -0700860 return false;
861 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800862 }
863
Josh Gao07db1192015-11-07 15:38:19 -0800864 bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
865 if (!dst_isdir) {
Josh Gao05786772015-10-30 16:57:19 -0700866 if (srcs.size() > 1) {
867 sc.Error("target '%s' is not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700868 return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800869 } else {
Josh Gao05786772015-10-30 16:57:19 -0700870 size_t dst_len = strlen(dst);
Josh Gao12a2ae92015-11-07 15:27:26 -0800871
872 // A path that ends with a slash doesn't have to be a directory if
873 // it doesn't exist yet.
Josh Gao1a025302015-11-09 11:12:14 -0800874 if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
Josh Gao05786772015-10-30 16:57:19 -0700875 sc.Error("failed to access '%s': Not a directory", dst);
Elliott Hughesaa245492015-08-03 10:38:08 -0700876 return false;
Elliott Hughes5c742702015-07-30 17:42:01 -0700877 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800878 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800879 }
Elliott Hughesaa245492015-08-03 10:38:08 -0700880
Josh Gao05786772015-10-30 16:57:19 -0700881 for (const char* src_path : srcs) {
882 const char* dst_path = dst;
Josh Gao12a2ae92015-11-07 15:27:26 -0800883 unsigned src_mode, src_time;
884 if (!sync_stat(sc, src_path, &src_time, &src_mode, nullptr)) {
885 return false;
886 }
887 if (src_mode == 0) {
Josh Gao05786772015-10-30 16:57:19 -0700888 sc.Error("remote object '%s' does not exist", src_path);
889 success = false;
890 continue;
891 }
892
Josh Gaof96dc732015-11-11 15:10:53 -0800893 if (S_ISREG(src_mode)) {
Josh Gao05786772015-10-30 16:57:19 -0700894 std::string path_holder;
Josh Gao07db1192015-11-07 15:38:19 -0800895 if (dst_isdir) {
896 // If we're copying a remote file to a local directory, we
Josh Gao1a025302015-11-09 11:12:14 -0800897 // really want to copy to local_dir + OS_PATH_SEPARATOR +
898 // basename(remote).
Josh Gao07db1192015-11-07 15:38:19 -0800899 path_holder = android::base::StringPrintf(
Josh Gao1a025302015-11-09 11:12:14 -0800900 "%s%c%s", dst_path, OS_PATH_SEPARATOR,
901 adb_basename(src_path).c_str());
Josh Gao07db1192015-11-07 15:38:19 -0800902 dst_path = path_holder.c_str();
Josh Gao05786772015-10-30 16:57:19 -0700903 }
904 if (!sync_recv(sc, src_path, dst_path)) {
905 success = false;
906 continue;
907 } else {
Josh Gao12a2ae92015-11-07 15:27:26 -0800908 if (copy_attrs &&
909 set_time_and_mode(dst_path, src_time, src_mode) != 0) {
Josh Gao05786772015-10-30 16:57:19 -0700910 success = false;
911 continue;
912 }
913 }
Josh Gao12a2ae92015-11-07 15:27:26 -0800914 } else if (S_ISDIR(src_mode)) {
Josh Gao07db1192015-11-07 15:38:19 -0800915 std::string dst_dir = dst;
916
917 // If the destination path existed originally, the source directory
918 // should be copied as a child of the destination.
919 if (dst_exists) {
920 if (!dst_isdir) {
921 sc.Error("target '%s' is not a directory", dst);
922 return false;
923 }
924 if (!adb_is_separator(dst_dir.back())) {
925 dst_dir.push_back(OS_PATH_SEPARATOR);
926 }
927 dst_dir.append(adb_basename(src_path));
928 }
929
930 success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(),
931 copy_attrs);
Josh Gao05786772015-10-30 16:57:19 -0700932 continue;
933 } else {
934 sc.Error("remote object '%s' not a file or directory", src_path);
935 success = false;
936 continue;
937 }
938 }
939
940 sc.Print("\n");
941 return success;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800942}
943
Elliott Hughesaa245492015-08-03 10:38:08 -0700944bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
Elliott Hughesaa245492015-08-03 10:38:08 -0700945 SyncConnection sc;
946 if (!sc.IsValid()) return false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800947
Josh Gaod9731572015-11-03 15:23:03 -0800948 return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800949}